先说个背景:我这个项目的代号叫AnyPS5,灵感纯粹是被自己桌面上那堆外设逼出来的。PS5 主机、外置硬盘、回音壁、HDMI 切换器、USB Hub、充电底座……每一样单独看都没问题,叠在一起就是一场灾难。每次开机要依次开四个开关,关机又要反过来操作一遍,等到想玩的时候人已经坐在沙发上不想动了。所以当时我就定了一个调子:不管它是 PS5、XSX 还是 Switch,不管外设是哪个牌子哪一年出的,这套系统得能“Any”都管得住——这也是名字的由来。
这篇内容不是某个成品工具的推广,而是我基于开源硬件和手头现成设备,做的一套外设电源与状态联动管理系统。核心目标很简单:在不动主机系统、不做任何破解、不改装主机内部的前提下,用外围设备把“开机→切换信号→开音响→开灯光→关机→断外设电源”这一整串动作自动化。整个项目从硬件选型到固件编写,到踩坑调试,再到接回家中自动化平台,前后花了三个多月。本文把完整的方案、接线、代码思路、踩坑链路都摊开讲,适合有一定动手能力、想让主机游戏体验更“一体化”的人参考。如果你完全没碰过微控制器开发,也能按着步骤做出来,只是需要多准备一点耐心。
1. 一台PS5引发的桌面爆炸:项目起因与设计取舍
1.1 设备堆叠的真实痛点
先说清楚我到底在烦什么。很多人觉得“不就多按几次开关嘛”,但当你把 PS5、显示器/电视、音响、采集卡、灯光、外置硬盘全堆在一起后,问题就不只是“多按几次”了。
第一个痛点是信号链路。PS5 接 HDMI 切换器,切换器再接显示器和回音壁。光这条链路上就有三个设备需要保持正确的开关顺序:先开切换器,再开 PS5,最后开音响。顺序错了会出现握手失败、黑屏几秒、音响不出声。这个问题在纯手动场景下几乎每天遇到,因为人会忘。
第二个痛点是待机功耗。PS5 的待机模式本身功耗不高,但它拖着的外置硬盘、USB Hub、灯光电源,全是实打实一直在耗电的。我测试过,一套外设待机状态下大概耗 15 到 20 瓦,一个月下来就是十几度电,完全是在浪费。
第三个痛点是物理按键损耗。每天按开关、按遥控器,看起来没什么,但 HDMI 切换器的按键是出了名的脆,按半年就会出现接触不良。我当时用的那台切换器就是按键先挂掉的,后来改造完才知道这玩意儿可以完全不用手按。
所以问题的本质不是“设备太多”,而是设备之间没有任何联动逻辑。它们各自为政,管理成本全部摊在用户身上。这才是我想解决的真正问题。
1.2 为什么自己做而不是买成品
市面上有没有类似成品?有。要么是智能插座单品,要么是带红外遥控的万能控制器,再高端一点有 HDMI 矩阵切换器加中控系统。但我全看了一圈之后发现三个硬伤:
单点控制不等于联动。智能插座能控制电源,但它不知道 PS5 是开着还是待机,也没法和 HDMI 信号切换联动。你还是要自己判断“现在该开还是该关”。
成品中控价格离谱。带串口控制、红外学习的商用中控,价格直接上千。为了管一台游戏机花这个钱,我觉得不划算,而且很多商用设备是给会议室、门店用的,放在家里既不灵活也占地方。
联动逻辑没法定制。我要的“按下手柄PS键→主机唤醒→切换器切到对应输入口→音响开机→灯光亮起”这一套流程,没有任何成品能直接做到,因为它们缺一个关键能力:感知主机状态。
基于这三点,我确定自己做。总成本控制在几十元左右,核心物料就是一块微控制器开发板、一个红外接收头、一个红外发射管、几个继电器模块和一个小电源。技术栈全部走开源方案,坏了能换,逻辑能改,不依赖任何云端服务。
1.3 方案选型的三个核心原则
做之前我先立了三条原则,后面所有决策都围绕这三条来,事实证明非常有用。
原则一:稳定优先于花哨。我不需要音效反馈、OLED动画、手机App遥测这些锦上添花的功能。这系统天天在跑,稳定性就是第一位的。任何可能引入误判、误触发的功能都直接砍掉。
原则二:能用协议沟通就别用物理模拟。能通过红外编码来控制的设备,就用红外;能通过串口、网线/Hub 传递状态的,就用状态读取。只有协议完全走不通的设备,才去考虑继电器切电源这种“物理大招”。
原则三:断电安全必须兜底。所有被控设备里,只有外置硬盘对“突然断电”最敏感。虽然硬盘自身也有断电保护,但在设计上我还是给硬盘供电单独走一路可编程延时继电器,主机真进入关机状态后才切断硬盘电源,避免任何一次误伤数据的可能性。
这三条原则定下来,后面的硬件选型和固件结构就顺理成章了。
2. 硬件矩阵:从微控制器到HDMI切换器的选型与接线
2.1 核心硬件清单
我最终用到的硬件非常朴素,全部是常见零件:
主控板:一个 ESP32 开发板。选它不是因为性能多强,而是因为它带 Wi-Fi 和足够的GPIO引脚,以后接家庭自动化平台方便。如果你只想本地跑、不接网络,用普通单片机开发板也行,成本还能再低一点。
红外接收头:用于接收 PS5 手柄的无线信号?严格说不算,它接收的是红外遥控器信号。但我这里用它的主要用途是“学习”遥控码和环境红外信号,方便联动老设备。
红外发射管:用来替代 HDMI 切换器和音响的遥控器,把它们的遥控码通过开发板重发出去。
继电器模块:用来控制 220V 侧的设备电源。我用了 4 路继电器板,分别控制外置硬盘、灯光、音箱备用电源、副显示器。控制信号全走 3.3V GPIO。
三路 HDMI 切换器:核心切换设备,带串口控制接口。这一步很关键,因为带串口的切换器可以直接用代码切换输入口,不用模拟遥控按键。
状态屏:一个小 OLED,128×64,用来显示当前状态——哪个设备在线、当前输入通道、是否处于待机态等。可选项,纯锦上添花。
如果手头已经有普通单片机板和一堆杜邦线,这套系统的物料成本大概就一顿快餐钱。下面是我最终的接线布局。
2.2 接线布局与 GPIO 分配
写固件前先规划 GPIO,否则后面对着代码理线会非常痛苦。我直接放结论表格:
| 功能 | GPIO 引脚 | 连接目标 | 说明 |
|---|---|---|---|
| 红外接收头 | GPIO4 | 红外接收模块 OUT | 用于接收遥控信号 |
| 红外发射管 | GPIO5 | 红外发射模块 IN | 用于发射遥控码 |
| 继电器1(外置硬盘) | GPIO12 | 继电器模块 IN1 | 控制硬盘电源 |
| 继电器2(灯光) | GPIO13 | 继电器模块 IN2 | 控制氛围灯 |
| 继电器3(音箱备电) | GPIO14 | 继电器模块 IN3 | 控制音箱电源备份 |
| 继电器4(副显示) | GPIO15 | 继电器模块 IN4 | 控制副显示器电源 |
| 切换器串口 TX | GPIO16 | 切换器 RX | 发送串口指令 |
| 切换器串口 RX | GPIO17 | 切换器 TX | 接收切换器状态 |
| OLED SDA | GPIO18 | OLED SDA | I2C 数据线 |
| OLED SCL | GPIO19 | OLED SCL | I2C 时钟线 |
| PS5 供电检测点 | GPIO34 | PS5 USB 口 供电 | 读取电压判断开关机状态 |
这里有两个重要的细节:
第一个是PS5 供电检测点接 GPIO34。PS5 的 USB 口在关机状态下仍会供电,但电压特征和待机/运行时不同。我用一个分压电路把 USB 口的电压降到微控制器能安全读取的范围内,再通过 ADC 读取数值。这一步是整个“状态感知”的根基,后面详细说。
第二个是继电器模块必须分开供电。如果继电器和主控共用同一个电源,继电器吸合的瞬间会产生大电流冲击,轻则让主控重启,重则烧掉 GPIO。我直接用了一个 5V 2A 的小电源给继电器模块单独供电,只用 GPIO 输出开关信号,不取电。
接线完成后先用面包板跑通,确认每个 GPIO 的逻辑电平没问题,再往洞洞板上焊。直接上 PCB 是自找麻烦,因为后期一定会调整引脚。
2.3 供电隔离与抗干扰处理
这部分看起来“玄学”,但实际影响非常大。最早我用的是一个廉价电源直接给全板供电,结果每次继电器一吸合,OLED 就闪一下、红外发射偶尔失灵。后来我做了三件事解决:
- 主控独立供电:ESP32 的 3.3V 由单独的稳压模块输出,不再从继电器电源上取。
- 信号线远离 220V 线:所有信号走线(红外、串口、GPIO)尽量贴着板子边缘,和继电器端的高压线保持 3 厘米以上距离。
- 红外发射管串电阻限流:这个很多人会忽略,红外发射管如果不限流,长时间工作会发烫、光强衰减,距离越来越近。我串了一个 10Ω 左右的电阻,让它稳定工作在安全的电流区间。
做完这三件事后,OLED 不再闪,继电器吸合瞬间也没再触发过主控重启。所以如果你做完之后发现“神bug”不断,先别怀疑代码,先从供电和走线排查。
2.4 装壳与走线心得
系统稳定之后,我在网上买了一个公模塑料壳,把所有板子、模块、电源装进去。走线用了不同颜色的杜邦线区分功能:红色供电、黑色地线、绿色信号、黄色控制线。壳子顶部开了一个小孔给红外接收头,侧面开了串口线出口,前面板开了 OLED 窗口。
这里唯一想提醒的是:接线端子一定要买带螺丝锁紧的,不是插拔式的。插拔式端子看着方便,但震动和热胀冷缩之后非常容易松动。我调试期间至少有三次因为端子松动导致误判“系统坏了”,最后全换成了螺丝端子才算根治。
3. 固件核心:状态感知、按键面板与串口通信的实现细节
3.1 状态感知不是“看灯”而是“看电位”
这是整个项目最核心的设计。你要联动一套设备,首先得知道主机什么时候开机、什么时候关机、什么时候待机。看灯是不行的,机器上的呼吸灯没法接进电路;只能从电气特征入手。
我最终采用的方式是读取 PS5 USB 口的供电电压特征。在 PS5 开机的不同阶段,USB 口输出电压会有可测量的差异:彻底关机后,USB 口基本无输出或输出极低;待机状态下,USB 口会有稳定的小电压输出;启动运行中,USB 口输出稳定且偏高。通过对这个电压做多档 ADC 转换,我就能在软件里把主机状态分成三类:SHUTDOWN、STANDBY、RUNNING。
当然,不同版本的主机、不同固件版本的 USB 策略可能略有差异,所以我在学习模式里做了一步“标定”:插上主机后,分别记录关机、待机、运行三个状态的电压读数,把阈值写进配置。这样即使设备换代,重新标定一次就能继续用。
这个细节点是整个联动逻辑正确性的前提。先有状态感知,后有联动。如果这一步偷懒,后面全是空中楼阁。
3.2 按键面板与去抖逻辑
按键面板我设计了三个物理按键:一键开机、一键关机、一键切换信号源。按下的瞬间 GPIO 会读到低电平,但在真实环境下,按键触点会出现连续多次抖动。如果不做去抖,一次按键可能会被识别成三四次操作,进而触发多次红外发射、重复切通道。
去抖逻辑我用了最经典的时间窗口方式:检测到电平变化后,先等待 20ms 再看一次电平是否稳定,如果稳定则确认为有效按键。实测下来,20ms 去抖在所有我试过的按键上都表现稳定。如果用的是质量很差的按键,可以适当加到 50ms,但响应手感会略钝。
另外我在按键处理里加了一个“长按开关机”的逻辑:短按是单步操作,长按超过 1 秒则执行整套联动流程。这样一个按键可以实现两种行为,实际使用下来非常顺手。
3.3 串口协议与状态上报
HDMI 切换器带串口控制,这意味着我不需要学习它的遥控码,直接通过串口发指令就能切换通道。我用的是最基础也是兼容性最好的方式——固定波特率、ASCII 指令。比如发送S1就切换到输入1,发送S2切换到输入2,发送STATUS返回当前通道。
在实际使用中,串口通信要特别注意一点:指令结尾必须带上回车换行符,否则有些设备不识别。另一个坑是波特率——我手上这一台切换器出厂默认 9600,但同类产品有 115200 的,不同品牌差异很大。接上后先发一条STATUS看返回是否乱码,乱码就换波特率逐一试,直到返回内容符合预期。
状态上报方面,ESP32 会把当前主机状态、切换器通道、继电器状态汇总成一个 JSON 字符串,通过串口发给接在上位的家庭自动化平台。这个稍后单独展开。
固件主循环的简化版本大致是这样:
void loop() { // 1. 读取 PS5 供电检测点的 ADC 值 int ps5Status = readPS5PowerState(); // 2. 如果有状态变化,执行对应动作 if (ps5Status != lastPS5Status) { handlePS5StateChange(ps5Status); lastPS5Status = ps5Status; updateOLED(); } // 3. 扫描按键,做去抖和动作分发 scanButtons(); // 4. 处理串口接收到的指令 handleSerialCommands(); // 5. 每 5 秒上报一次状态快照 static uint32_t lastReportMs = 0; if (millis() - lastReportMs > 5000) { publishStatusSnapshot(); lastReportMs = millis(); } }真实代码比这长不少,主要是多了些防抖标志位和状态机转移,但骨架就是这个样子。
3.4 开机时序与电力安全逻辑
整套联动流程里,我最在意的是时序。开机时如果所有设备同一瞬间通电,冲击电流很大,而且 HDMI 握手可能失败;关机时如果直接同时切断硬盘电源,又可能碰到正在读写的数据。
所以我在固件里给每个动作定义了明确的先后顺序:
- 开机流程:先给切换器通电并等待 3 秒让设备自检,再给显示设备通电,随后给 PS5 发开机信号(这里我用的是通过红外发射功能区发出的开机电码),等待 5 秒待 PS5 完全进入系统,最后才给音响和灯光通电。
- 关机流程:先给 PS5 发关机信号,等待 10 秒让系统进入待机状态,再依次断掉灯光、音响电源,最后延时 5 秒后切断外置硬盘电源。这一步的延时很关键,等于给了硬盘一个缓冲时间,避免数据损伤。
这套时序在固件里用状态机实现,每一个动作完成之后记录一个时间戳,再等待下一个动作触发,而不是用阻塞式delay()。因为阻塞式延时会让整个系统在等待期间没法响应按键和串口指令,体验非常差。
4. 调试期踩坑实录:红外干扰、半待机误判与接线松动
4.1 红外干扰误触发:状态机被“幻影按键”打乱的排查链路
系统运行了大概一周后出现一个诡异现象:晚上的时候,PS5 会自己开机。第一次遇到时我还以为是误触手柄,后来连续三晚都这样,才意识到肯定有系统性问题。
排查过程是这样的:
第一步,我怀疑是 PS5 的自动唤醒功能,比如 HDMI 联动、网络唤醒。检查之后发现这些选项全都关着。
第二步,我怀疑是红外发射代码有 bug。为了验证,我在固件里加了一段记录日志:每次红外发射时,把发射的原因、时间、触发源写到日志里,通过串口导出。结果发现,红外发射代码根本没有在异常时间段执行过。
第三步,我开始怀疑环境红外干扰。把红外接收头接上逻辑分析仪,记录一整晚的信号。第二天看波形时发现了规律:每天半夜,接收头都会收到一组和开关机电码非常相似的红外信号。仔细比对后发现,这是某品牌电视遥控器的“待机”指令码,可能是在电视待机时周期性发送的。
问题清楚了:我用的红外接收头是没有解码的裸接收头,它会把任何红外信号都转成脉冲输出,只要波动特征匹配,固件就误认为“接收到开机指令”。解决方案也很直接:在接收头前面加一个遮光罩,只留一个朝向正前方的小开孔,并从固件里对收到的红外码做二次校验——要求连续收到两次相同码且间隔在固定范围内才执行动作。加了这个双重防护之后,误触发彻底消失。
这个坑的教训是:红外接收头本身是“耳朵”,但耳朵不能无差别地听。环境里的红外信号比你想的要多得多,设计时必须人为加一道过滤。
4.2 半待机误判:为什么只看供电电压会翻车
第一次标定完电压阈值后,我以为状态识别稳了。结果用了几天发现一个矛盾现象:主机明明在待机,系统却认为主机还在运行,导致联动流程不完整,副显示器电源一直不肯关。
我排查到最后发现,原因是“待机”和“运行”两个状态的电压差异实在太小,只有几十毫伏。而这个电压本身还会随着电源质量波动。换句话说,只看 ADC 数值做阈值判断,等于在拿一个不太稳定的指标做决策,误判是必然的。
解决思路是引入第二个状态判断维度。我在 PS5 的 HDMI 输出线上做了一个简单的信号检测电路,当主机的 HDMI 输出有同步信号时,检测电路会输出高电平;没有信号时输出低电平。这样固件就同时拥有了两个判断依据:USB供电电压档位和HDMI同步信号。状态判断逻辑变成:
USB电压低 + HDMI无信号→ 关机USB电压中 + HDMI无信号→ 待机USB电压高 + HDMI有信号→ 运行中
这个二元判断组合让误判降低到几乎为零。这也是我踩坑后最大的架构调整,它比单纯调阈值靠谱太多。如果你的设备没法接 HDMI 信号检测,也可以用另一个思路——通过路由器后台轮询主机 IP 是否在线。虽然响应慢一点,但也能起到辅助判断作用。
4.3 接线断路与继电器粘连
第三次踩坑发生在系统稳定运行一个月后。某天我发现外置硬盘的电源一直断不开,指示灯始终亮着,但继电器模块上的指示灯明明已经灭了。
拆开壳子一量,继电器输出端的两根线之间居然有 200Ω 左右的电阻。这是标准的继电器触点粘连症状。原因是那路继电器长期在接通状态下传导硬盘的大电流,触点发热氧化,最终导致无法断开。换上新的继电器后,我在固件里加了一条保护逻辑:任何一路继电器在连续工作超过 6 小时后,系统会定期做一次短暂断合测试,确保触点状态正常。虽然这会产生几毫秒的电源闪断,对硬盘来说完全可以接受,但能避免触点长期积热。
另外,我检查后发现断电失灵还有另一个推波助澜的因素:接线端子松动导致继电器线圈供电电压不足。线圈电压不够,触点开关会卡在半路,长时间这样也会烧触点。这也验证了 2.4 节那个结论——线端子必须用螺丝锁紧。
4.4 验证清单与回归测试
把整个系统重新整理稳定之后,我做了一份手动验证清单,每次改动代码或硬件都要跑一遍:
| 测试项 | 预期行为 |
|---|---|
| 待机状态手动按开机键 | 切换器、显示设备按顺序上电,红外电码送给主机 |
| 运行中状态手动按关机键 | 主机进入待机,副显示器和灯光依次断电,硬盘延时断电 |
| HDMI 通道手动切换 | 切换器串口返回对应通道状态,OLED 显示同步更新 |
| 红外码学习 | 新遥控码可学习、可保存,重启后仍可用 |
| 断网运行 | 本地按键和串口控制完全不受影响 |
| 网线恢复 | 状态上报自动恢复,不需要重启 |
| 首轮接线检查 | 所有端子重新锁紧,继电器触点无异常 |
这套验证清单的覆盖度不算高,但对一个日常家用系统来说已经够用。核心原则就一条:每次只改一个变量,回归测试必须做全套。跳过任何一个测试项,都可能把上一个坑再踩一遍。
5. 接入家庭自动化后的完整行为模式与复盘输出
5.1 “游戏模式”联动场景
系统单独跑一个月之后,连上了家庭自动化平台,把 PS5 纳入到场景里。所谓“游戏模式”,实际上是把 AnyPS5 的状态上报和自动化平台的场景触发能力结合起来:
- 当 AnyPS5 上报
RUNNING状态时,自动化平台自动执行:客厅吸顶灯调暗、落地灯色温切到暖黄、窗帘拉上一半、桌面氛围灯亮起、空调切到静音模式。 - 当 AnyPS5 上报
STANDBY时,自动化平台延迟 1 分钟后执行反向操作:灯光恢复、窗帘打开、空调恢复到正常模式。 - 当 AnyPS5 上报
SHUTDOWN时,所有联动设备全部复位。
实现方式不复杂。ESP32 每 5 秒通过 Wi-Fi 向家庭自动化平台上报一个 JSON 状态,自动化平台根据state字段触发对应场景。ESP32 用的是轻量的 HTTP POST,不依赖任何云服务。
这个场景跑起来之后,我最大的感受是:联动逻辑的延迟感知几乎不可闻。从按下手柄 PS 键到灯光调节完成,不超过 3 秒。虽然和“秒开”还有一点距离,但在实际体验上已经完全够用,反而比一开始想象的“所有动作瞬间完成”更真实、更不突兀。
5.2 状态上报与远程查看
除了自动化联动,状态上报也带来了一个额外收益——可以远程查看主机状态。在家庭自动化平台的仪表盘上,我直接能看到当前 PS5 处于什么状态、HDMI 切换器在哪一路、各继电器是否通电。出门在外也能通过手机看主机是不是还开着,有没有异常待机。
这套汇报体系还解决了另一个痛点:如果家里有人乱按遥控器,把 HDMI 通道切乱了,我不用回家慢慢猜是哪里的问题,直接看状态历史记录就知道什么时候切换过通道、触发源是什么。排查问题的时间从“半小时”降到“一分钟”。
5.3 一个月使用后的复盘输出
系统带状态上报跑了整整一个月,我导出日志做了个简单统计,发现几条很有意思的数据:
- 一个月内“一键开机联动”被执行了 47 次,成功率 100%。
- “一键关机联动”被执行了 39 次,其中有一次因为主机正在写入数据,系统主动推迟了硬盘断电时间,成功避开了潜在风险。
- 红外误触发在加了遮罩和双重校验之后,触发次数为零。
- 平均每次手动开机到所有外设就绪的时间是 12 秒,比起之前手动操作节省了约 30 秒。虽然单次不算多,但每天用,一年下来就是 5 个小时以上的时间省下来了。
这些数据让我确信,当初“只看状态、不改机器”的设计路线是对的。整个系统没有触碰主机的任何限制,纯粹靠外围感知和外围控制完成了联动。这让项目的可维护性变得非常高,不会因为某个固件更新就彻底失效。
5.4 扩展方向与组件复用
这套系统的思路并不局限于 PS5。把状态感知部分抽象出来之后,可以套用到任何带 USB 供电的消费电子设备上。我已经在规划把同一套主控板接到另一台电视上,通过电视 USB 口的供电特征判断电视开关状态,从而联动回音壁和播放器电源。换掉 HDMI 切换器协议部分,也能接入投影仪、采集卡等设备。
组件复用方面,红外学习模块可以脱机保存最多 32 组码,足够覆盖家中常备遥控器;串口切换器模块也能直接换成支持网络控制的版本,这样就能去掉红外发射管,纯走 TCP/IP 控制。对我自己而言,这套架构最大的价值是提供了一个“设备状态感知 + 联动控制”的通用框架,以后接什么设备都只是换传感器的差别。
最后说一个使用细节。我给所有连接线的两端都贴了标签纸,写上设备名和引脚号。这套系统在调试期天天拆装,多亏了标签才没有在第三次接线时精神崩溃。如果你打算复刻这套方案,建议从第一天就养成这个习惯——这比任何“优化代码”的建议都实在。