1. 项目概述打造你的专属桌面天气站每次想看天气都得掏出手机解锁、打开App是不是觉得有点麻烦如果你和我一样喜欢把有用的信息“摆”在眼前那么这个基于CircuitPython和LED矩阵的天气显示器项目绝对值得你花一个周末的时间来折腾。它不只是一个显示温度的“电子钟”更是一个融合了嵌入式开发、网络API调用和硬件交互的微型物联网作品。想象一下在你的书桌或客厅一角一块64x32像素的RGB LED矩阵正静静地展示着室外的温度、湿度、天气状况甚至风速所有数据都通过Wi-Fi从云端实时获取并优雅地滚动显示。这不仅仅是获取信息更是一种极客范儿的装饰和对自己动手能力的证明。这个项目的核心在于它巧妙地连接了三个世界物理的硬件世界LED矩阵和微控制器、本地的逻辑世界CircuitPython固件以及云端的服务世界OpenWeather API。我们使用的Adafruit Matrix Portal或Metro M4 Airlift板卡内置了ESP32协处理器它负责处理繁琐的Wi-Fi连接和网络请求而主控芯片则专注于驱动那块拥有2048颗独立LED的炫酷屏幕。整个系统的“大脑”是CircuitPython它是MicroPython的一个分支专为教育和小型嵌入式设备优化让你能用熟悉的Python语法快速操控硬件无需复杂的编译和烧录过程就像在电脑上写脚本一样简单。无论你是刚接触硬件的Python开发者还是想给Arduino项目增加点网络功能的硬件爱好者这个项目都是一个绝佳的起点。它涵盖了从硬件组装、固件刷写、库管理、API密钥申请、网络配置到代码调试的完整流程。接下来我会带你一步步走完整个过程并分享那些官方教程里可能不会细说的“坑”和技巧让你不仅能成功复现更能理解背后的“为什么”。2. 硬件选型与核心思路解析在动手之前搞清楚我们有哪些选择以及为什么这么选能让你后续的步骤更加顺畅。这个项目提供了两条主要的硬件路径它们最终实现的功能一致但成本和复杂度略有不同。2.1 核心硬件方案对比你可以根据手头的预算和焊接熟练度在以下两种方案中二选一方案一Matrix Portal一体化方案推荐新手这是Adafruit推出的“全家桶”式解决方案。Matrix Portal本质上是一块集成了ESP32 Wi-Fi模块、MicroSD卡槽和RGB矩阵驱动电路的单板。它的最大优点是开箱即用。你不需要焊接任何排针只需要像拼乐高一样将LED矩阵的排线插到板子上对应的接口接上电源和USB线硬件部分就完成了90%。它专为LED矩阵显示和网络应用设计所有引脚和功能都已优化省去了很多配置和调试的麻烦。对于希望快速看到成果、或者对焊接不太有信心的朋友来说这是最稳妥的选择。方案二Metro M4 Airlift RGB Matrix Shield分体式方案适合爱折腾的玩家这个方案更具模块化色彩。你需要三样核心部件一块Metro M4 Airlift主控板、一块RGB Matrix Shield扩展板以及LED矩阵本身。Metro M4 Airlift是一块功能强大的微控制器板基于ATSAMD51芯片并板载了ESP32作为Wi-Fi协处理器。RGB Matrix Shield则是一个“翻译官”负责将主控板的数字信号转换成LED矩阵能理解的复杂时序信号。这个方案需要你亲手将排针焊接到扩展板上再将扩展板插到主控板上。它的好处是灵活性更高Metro M4 Airlift本身就是一个通用的开发板完成这个项目后你可以轻松拆下扩展板用它去做其他项目。同时分体采购有时在总成本上可能略有优势。注意无论选择哪个方案LED矩阵本身建议选择64x32像素、4mm点间距的型号。这个分辨率在显示文字和简单图标时清晰度足够尺寸也适合桌面摆放。点间距决定了像素密度4mm是一个在观看距离和细节表现上比较平衡的选择。2.2 为什么是CircuitPython你可能会问为什么不用更常见的Arduino (C/C) 或者MicroPython这正是CircuitPython的巧妙之处。极致的开发体验CircuitPython将你的开发板变成一个U盘名为CIRCUITPY。你只需用任何文本编辑器如VS Code、Mu Editor甚至记事本修改板子上的code.py文件保存后代码会自动重启运行。这实现了真正的“保存即运行”调试效率极高特别适合快速迭代和初学者。丰富的库生态Adafruit为CircuitPython维护了超过数百个“库”Library涵盖了传感器、显示器、网络协议等几乎所有你能想到的硬件功能。这些库都经过精心封装通常只需几行代码就能驱动复杂的硬件比如我们这个项目中的adafruit_matrixportal库它把网络请求、矩阵显示、图形绘制等底层细节全部打包好了。Python的亲和力Python语法简洁易懂拥有庞大的开发者社区。对于从软件转向硬件的开发者或者希望教授编程与硬件的教育者来说CircuitPython大大降低了入门门槛。处理像JSON这样的网络数据格式在Python中就是几行代码的事远比在C语言中手动解析要简单得多。2.3 系统工作原理全景图理解了硬件和软件的选择我们再来俯瞰整个系统是如何协同工作的上电与初始化设备启动运行code.py。首先它读取settings.toml文件中的Wi-Fi密码和API密钥然后连接到你指定的无线网络。数据获取连接成功后代码会构建一个指向OpenWeather API的URL。这个URL包含了你的地理位置如“Beijing, CN”和单位制公制/英制。通过HTTP GET请求从OpenWeather的服务器获取一份JSON格式的天气数据包。数据解析CircuitPython的adafruit_requests库负责接收这个JSON包。然后在openweather_graphics.py这个我们提供的图形处理模块中代码会像走迷宫一样按照预定的路径例如[‘weather’][0][‘description’]从JSON中提取出我们需要的信息温度、湿度、天气描述、图标代码等。数据呈现提取出的数据被传递给图形模块。这个模块做了三件事图标显示根据API返回的图标代码如“01d”代表晴天从一张预制的位图weather-icons.bmp中裁剪出对应的图标显示在矩阵左侧。文本渲染使用adafruit_bitmap_font库将温度数值如“22°C”和地点名称渲染为像素字体。滚动效果对于湿度、描述、风速等较长的文本利用adafruit_display_text的滚动标签功能让文字从屏幕右侧平滑滚动进入。循环与节流系统进入主循环。为了避免频繁请求API导致服务器封锁或浪费电力代码设置了节流机制每小时同步一次网络时间用于显示每十分钟才重新获取一次天气数据。在等待间隔里它只是不断地更新滚动文本的动画帧。这个流程清晰地展示了一个典型物联网数据终端的核心逻辑连接 - 获取 - 解析 - 显示。接下来我们就从零开始一步步把它实现出来。3. 硬件组装与电路连接实操选择好方案后我们进入动手环节。这里我以更常见、也更推荐新手的Matrix Portal方案为例详细讲解组装过程。如果你用的是Metro M4方案原理相通主要是焊接排针和连接排线的方式不同请参考输入材料中的对应章节。3.1 开箱检查与准备工作首先请确认你手头有所有这些部件Adafruit Matrix Portal 主板 x164x32 RGB LED矩阵 (4mm pitch) x1USB-C 数据线用于供电和编程x15V/2.5A以上的直流电源适配器带桶形插头x1可选LED扩散亚克力板、Uglu Dashes胶点、支架在开始之前先给Matrix Portal做个“体检”。翻到板子背面你会看到两个铜柱Standoff上面可能贴着黄色的保护胶带。这个胶带必须撕掉它是生产过程中防止氧化的如果不撕你的电源将无法通过它输送给LED矩阵。用指甲或镊子小心地揭下这两个黄色圆形贴纸。3.2 连接LED矩阵这是最关键的一步连接错误可能会损坏设备。电源线连接找到那根带有红色和黑色鳄鱼夹或铲形插头的电源线。将红色线连接到板子背面标注了“5V”的铜柱上黑色线连接到标注“GND”的铜柱上。使用小螺丝刀拧紧确保接触牢固。电源线的另一端是一个4针的杜邦头插头。给矩阵供电在LED矩阵的背面找到一组4针的排针通常是唯一的一组。将电源线插头的红线一侧对准板上标有“5V”或“VCC”的丝印插入。这个插头有防呆设计方向反了是插不进去的但还是要仔细核对。数据排线连接拿出那根16针的灰色排线FFC排线。Matrix Portal板子的正面有元件的一面左侧有一个黑色的、带夹子的16针插座。打开夹子通常向上或向侧面扳动将排线金色触点一面朝上插入到底然后扣紧夹子固定。排线的另一端以同样的方向金色触点朝上插入LED矩阵背面的16针插座中。这个连接负责传输所有的图像数据。实操心得在处理FFC排线时一定要轻柔。插入前确保排线边缘平整没有翘曲。如果感觉阻力很大不要硬插检查一下方向和插座夹子是否完全打开。我曾因为排线没插到底导致屏幕显示花屏排查了半天才发现是接触不良。3.3 上电测试与初步检查在连接USB线到电脑之前先不要插上5V的桶形电源。仅通过USB线给Matrix Portal供电。此时LED矩阵可能不会亮或者只微弱地亮起一部分这是正常的因为USB的500mA电流不足以驱动全屏。打开电脑的文件管理器你应该能看到一个名为MATRIXBOOT或CIRCUITPY的U盘盘符出现。如果看到MATRIXBOOT说明板子处于引导加载模式等待刷入固件。如果看到CIRCUITPY恭喜你CircuitPython已经预装好了可以直接进行下一步。如果什么都没出现检查USB线是否支持数据传输很多手机充电线只能充电或尝试按一下板子上的Reset按钮。4. 软件环境部署与核心代码剖析硬件准备就绪现在我们来赋予它“灵魂”。这部分是项目的软件核心我会详细解释每一个步骤和代码段的意义。4.1 安装CircuitPython固件如果你的板子显示的是MATRIXBOOT盘符你需要先刷入CircuitPython固件。下载固件访问 circuitpython.org 在搜索框中选择你的板子型号如 Matrix Portal M4。下载最新的.uf2格式固件文件。进入引导模式确保板子通过USB连接到电脑。快速双击板子上的Reset按钮。板载的NeoPixel RGB LED会变成绿色如果变红说明USB连接有问题。此时电脑上会出现一个名为MATRIXBOOT的驱动器。刷入固件将刚才下载的.uf2文件直接拖拽或复制到MATRIXBOOT驱动器中。驱动器会自动弹出几秒后一个新的名为CIRCUITPY的驱动器会出现。这表明固件刷写成功。4.2 配置网络与API密钥这是连接互联网和天气服务的关键。所有配置都放在CIRCUITPY驱动器根目录下的settings.toml文件中。用文本编辑器新建或打开这个文件。# settings.toml - 你的秘密配置仓库 CIRCUITPY_WIFI_SSID 你的Wi-Fi名称 CIRCUITPY_WIFI_PASSWORD 你的Wi-Fi密码 # OpenWeather API 密钥 (免费注册获取) openweather_token 你的32位长字符串令牌 # Adafruit IO 用于时间同步 (免费账户) ADAFRUIT_AIO_USERNAME 你的Adafruit用户名 ADAFRUIT_AIO_KEY 你的Adafruit IO Key获取OpenWeather Token访问 OpenWeatherMap官网 注册一个免费账户。登录后在“API Keys”选项卡下系统会为你生成一个默认的Key一串由数字和字母组成的32位字符串。免费套餐通常足够个人使用有每分钟调用次数限制但对于我们每10分钟查询一次的项目来说绰绰有余。将这串字符复制到settings.toml的openweather_token后面。获取Adafruit IO信息用你的Adafruit账户登录 Adafruit IO 。点击页面左上角的“View AIO Key”。在弹出的窗口中你会看到Username和Active Key将它们分别填入配置文件中。Adafruit IO为我们提供了一个稳定可靠的时间服务器用于校准设备时钟。重要提示settings.toml文件包含了你的敏感信息。切勿将它上传到GitHub等公开代码仓库。.toml文件会被CircuitPython自动识别并加载为环境变量代码中通过os.getenv()来读取这是一种安全且方便的管理方式。4.3 安装必要的代码库CircuitPython的强大离不开丰富的库。我们需要将项目依赖的库文件复制到CIRCUITPY驱动器上的lib文件夹中。如果lib文件夹不存在就新建一个。你需要下载以下库文件可通过Adafruit的CircuitPython库包 Bundle 获取adafruit_matrixportaladafruit_bitmap_fontadafruit_display_textadafruit_requests.mpyadafruit_io(可选用于时间同步但adafruit_matrixportal网络部分已包含其功能)neopixel.mpy(通常已内置于固件)adafruit_bus_device(底层依赖)adafruit_display_shapes(可能被adafruit_matrixportal依赖)adafruit_esp32spi(网络依赖)将下载的.mpy或文件夹直接放入CIRCUITPY盘的lib目录下即可。4.4 主程序代码深度解析现在我们来深入看看核心的code.py理解它每一部分在做什么。# SPDX-FileCopyrightText: 2020 John Park for Adafruit Industries # SPDX-License-Identifier: MIT import time import board import microcontroller from digitalio import DigitalInOut, Direction, Pull from adafruit_matrixportal.network import Network from adafruit_matrixportal.matrix import Matrix import openweather_graphics # 1. 读取密钥 try: from secrets import secrets # 旧版方式现在我们用settings.toml except ImportError: print(WiFi secrets are kept in secrets.py, please add them there!) raise # 2. 单位制切换逻辑硬件交互 if hasattr(board, D12): # Metro M4方案使用D12引脚上的跳线帽 jumper DigitalInOut(board.D12) jumper.direction Direction.INPUT jumper.pull Pull.UP # 启用内部上拉电阻 is_metric jumper.value # 跳线帽接地短路时值为False英制断开时为True公制 elif hasattr(board, BUTTON_DOWN) and hasattr(board, BUTTON_UP): # Matrix Portal方案使用板载按钮 button_down DigitalInOut(board.BUTTON_DOWN) button_down.switch_to_input(pullPull.UP) button_up DigitalInOut(board.BUTTON_UP) button_up.switch_to_input(pullPull.UP) # 检测启动时的按钮状态并存入非易失性存储器(NVM) if not button_down.value: # 按钮被按下低电平 print(Down Button Pressed - 设置为公制) microcontroller.nvm[0] 1 # 在NVM的第一个字节存储1 elif not button_up.value: # 按钮被按下低电平 print(Up Button Pressed - 设置为英制) microcontroller.nvm[0] 0 # 在NVM的第一个字节存储0 # 从NVM读取之前保存的设置 is_metric microcontroller.nvm[0] else: is_metric False # 默认英制 # 3. 根据设置决定单位 if is_metric: UNITS metric print(单位设置为公制 (摄氏度, 米/秒)) else: UNITS imperial print(单位设置为英制 (华氏度, 英里/小时)) # 4. 设置查询地点和构建API URL LOCATION Beijing, CN # 格式城市名, 国家代码(ISO 3166) DATA_SOURCE http://api.openweathermap.org/data/2.5/weather?q LOCATION units UNITS # 从 settings.toml 中读取令牌 import os openweather_token os.getenv(openweather_token) DATA_SOURCE appid openweather_token # 5. 初始化显示和网络 matrix Matrix() network Network(status_neopixelboard.NEOPIXEL, debugFalse) # debugTrue可看网络日志 gfx openweather_graphics.OpenWeather_Graphics(matrix.display, am_pmTrue, unitsUNITS) # 6. 时间与数据刷新计时器 localtime_refresh None weather_refresh None # 7. 主循环 while True: # 每小时同步一次网络时间 if (not localtime_refresh) or (time.monotonic() - localtime_refresh) 3600: try: network.get_local_time() # 从Adafruit IO获取并设置RTC localtime_refresh time.monotonic() except RuntimeError as e: print(获取时间失败重试中..., e) continue # 每10分钟获取一次天气数据 if (not weather_refresh) or (time.monotonic() - weather_refresh) 600: try: # 关键步骤发起网络请求并解析JSON value network.fetch_data(DATA_SOURCE, json_path([],)) print(API返回数据:, value) # 将数据传递给图形处理模块进行显示 gfx.display_weather(value) weather_refresh time.monotonic() except RuntimeError as e: print(获取天气失败重试中..., e) continue # 更新滚动文本动画 gfx.scroll_next_label() time.sleep(0.05) # 控制滚动速度越小滚动越快代码逻辑精讲非易失性存储NVM的应用microcontroller.nvm[0]是CircuitPython提供的一个小容量、断电不丢失的存储空间。这里我们用它来保存单位制的选择。Matrix Portal板载按钮的检测只在启动时进行一次将结果写入NVM之后每次开机都读取这个值实现了设置的持久化。API URL的构造仔细观察DATA_SOURCE这个字符串。它包含了查询地点qBeijing,CN、单位制unitsmetric和最重要的令牌appid...。OpenWeather API正是通过这个完整的URL来识别用户并返回对应地点的数据。节流机制time.monotonic()返回一个单调递增的时间戳单位秒。通过记录上一次成功操作的时间weather_refresh并与当前时间比较差值大于600秒10分钟才执行新的网络请求。这是对API提供商的礼貌也是防止因网络错误导致循环频繁请求的有效手段。错误处理网络请求被try...except块包裹。一旦发生超时或服务器错误会捕获RuntimeError并打印错误信息然后通过continue跳过本次显示更新进入下一次循环重试。这保证了程序的健壮性不会因为一次网络波动而崩溃。4.5 图形与显示模块 (openweather_graphics.py)这个文件是项目的“视觉引擎”它负责所有绘制工作。其核心是display_weather(value)函数它接收解析后的天气数据字典然后解析数据从复杂的JSON对象中通过键值路径提取所需数据。例如温度位于[‘main’][‘temp’]天气描述位于[‘weather’][0][‘description’]。图标映射OpenWeather API返回一个图标代码如“04n”表示夜晚多云。项目附带了一个weather-icons.bmp文件它是一张包含了所有可能天气图标的长条形雪碧图Sprite Sheet。代码根据图标代码计算出该图标在雪碧图中的位置坐标然后使用displayio.TileGrid将其“切割”出来显示在屏幕指定位置。文本布局使用adafruit_display_text创建多个文本标签对象设置其字体来自fonts文件夹的.bdf点阵字体、颜色、位置。对于长文本将其设置为滚动标签scrolling_label。组管理CircuitPython的显示系统基于displayio.Group。我们可以把图标、温度文本、滚动文本等所有元素作为子对象加入一个主组self._display_group然后一次性更新到矩阵显示屏上效率很高。5. 进阶调试、优化与问题排查项目运行起来后你可能会遇到一些小问题或者想让它变得更好。这里分享一些实战中积累的经验。5.1 常见问题与解决方案速查表问题现象可能原因排查步骤与解决方案屏幕不亮或闪烁后熄灭电源功率不足。确保使用了5V/2.5A以上的独立电源适配器并通过桶形接口供电。USB口仅用于编程无法驱动全亮屏幕。屏幕显示乱码或花屏1. 数据排线接触不良。2. 刷新率或引脚配置错误。1. 检查FFC排线两端是否插紧金色触点是否朝上。2. 对于非Matrix Portal板子检查matrix Matrix()初始化时是否传入了正确的bit_depth、color_order等参数本项目代码已优化通常无需改动。无法连接到Wi-Fi1.settings.toml配置错误。2. 网络环境问题。3. 板子Wi-Fi模块故障。1. 仔细检查CIRCUITPY_WIFI_SSID和CIRCUITPY_WIFI_PASSWORD确保没有多余空格密码正确。2. 尝试将Network()初始化时的debug参数设为True在串口输出中查看连接过程。3. 重启路由器或将板子靠近路由器试试。提示KeyError或天气数据获取失败1. OpenWeather API密钥无效或未设置。2. 地理位置格式错误。3. 免费API调用次数超限。1. 确认openweather_token已正确填入settings.toml并在代码中通过os.getenv成功读取。2. 确保LOCATION格式为City, CountryCode国家代码是ISO 3166标准如US,CN,GB。可在OpenWeather网站搜索城市确认格式。3. 免费账户有调用频率限制请确认是否在别处过度使用该密钥。时间显示不正确1. 未配置Adafruit IO。2. 时区问题。1. 确保ADAFRUIT_AIO_USERNAME和ADAFRUIT_AIO_KEY已配置。虽然网络功能可能正常但时间同步需要此配置。2.network.get_local_time()默认可能使用UTC时间。如需本地时间可能需要修改adafruit_matrixportal网络库中的相关函数或自行在代码中增加时区偏移计算。按钮/跳线切换单位无效1. 硬件连接问题。2. NVM读取错误。1. 检查跳线是否确实短接了D12和GND或按钮是否正常。2. 对于Matrix Portal尝试在启动时长时间按住按钮约2秒确保程序检测到。可以添加print(microcontroller.nvm[0])来调试NVM值。5.2 功能优化与个性化定制基础功能运行稳定后你可以尝试以下改造让它更贴合你的需求显示更多信息OpenWeather API返回的数据非常丰富。你可以修改openweather_graphics.py轻松添加更多信息的显示例如体感温度 (feels_like)大气压强 (pressure)日出/日落时间 (sys.sunrise,sys.sunset)需要将Unix时间戳转换为可读时间。紫外线指数需要调用另一个API端点。自定义显示样式字体在fonts文件夹中替换其他.bdf点阵字体。注意字体高度不能超过矩阵的像素高度32像素。颜色在代码中修改label.color的值可以使用RGB元组如(255, 50, 0)代表橙色。可以尝试让温度值根据高低变色例如高温红色低温蓝色。布局调整图标、温度、滚动文本的x,y坐标位置创造独特的布局。降低功耗如果你希望它用电池供电可以考虑增加睡眠时间比如每30分钟更新一次天气。在深夜时段例如晚11点到早6点完全关闭屏幕显示通过matrix.display.brightness 0实现。使用其他天气API国内用户可能希望使用和风天气等本地服务。原理相同注册获取API Key查阅其接口文档修改DATA_SOURCE的URL构造方式和display_weather函数中的数据解析逻辑即可。5.3 添加亚克力扩散板裸眼的LED矩阵虽然亮眼但直视LED灯珠会有较强的颗粒感和眩光。添加一块磨砂亚克力扩散板可以极大地提升视觉质感让光线变得柔和均匀更像一个成熟的商业产品。测量与切割将LED矩阵放在黑色扩散亚克力板的保护纸上描出外框。使用线锯、勾刀或送到玻璃店/广告店切割出比面板四周略大1-2mm的尺寸以便安装。清洁撕掉亚克力两面的保护膜用眼镜布或屏幕清洁剂擦拭干净。粘贴使用Uglu Dashes这类透明双面胶点是最佳选择。在矩阵面板的四个角以及长边的中点位置贴上胶点然后对齐亚克力板均匀用力按压20-30秒。这种胶粘性强且可无损移除。效果安装后LED点光源会扩散成柔和的面光源文字和图标边缘更平滑在环境光下也更易读高级感瞬间提升。完成以上所有步骤你的专属物联网天气显示器就已经在稳定运行了。从一堆零件到一个能实时反馈世界信息的智能设备这个过程中你实践了硬件集成、嵌入式编程、网络通信和API调用——这些都是现代物联网开发的核心技能。这个小小的矩阵屏就像一扇通往物理计算世界的窗口希望它能激发你更多的创作灵感。