没有公网 IP、不改路由器端口映射、不装付费内网穿透客户端付费版—— 用一台 24 小时开机的 NAS 上的 Home Assistant 当中转站,实现异地一键开机 + 关机。
Windows 小工具,单 exe,纯标准库,配置全在界面里改。
场景很常见:家里主力机放在那,人在公司/外地,想用远程桌面连回去。
- 关机状态连不上,得先叫醒它 —— WOL 魔术包只能在同一个广播域里发,隔着公网发不出去。
- 用完忘了关,机器空转一整天 —— 需要一条能把"关机"送进去的通道。
两件事都卡在同一处:你人不在那个局域网里。
把一台 7×24 在线的设备(NAS / 软路由 / 树莓派)放到那个局域网里,让它当"驻场代理":
你(异地) 家里局域网
┌──────────┐ HTTPS / MQTT ┌──────────────┐ WOL 广播 ┌──────────┐
│ 笔记本 │ ───────────────► │ NAS │ ─────────► │ 目标电脑 │
│ 手机 │ │ Home Assist │ │ │
└──────────┘ ◄─────────────── └──────────────┘ ◄───────── └──────────┘
状态回传 MQTT 关机指令
- 开机:让 HA 在局域网内广播魔术包。它和目标机在同一个广播域,包发得出去。
- 关机:目标机上跑一个 MQTT 客户端(推荐 HASS.Agent),订阅 HA 下发的命令。
- 状态:目标机在线时自己上报,离线时消息自动过期,HA 拿到的就是真实状态。
HA 的网页/API 怎么从外网访问,是另一件事——IPv6 + DDNS、或者任意虚拟组网工具都行,本文不展开。
| 方案 | 问题 |
|---|---|
| 路由器端口映射 + 公网 IPv4 | 多数家宽没有公网 IPv4 了 |
| IPv6 直连目标机 | 目标机休眠/关机时没有网络栈,连不上;而且开机这一步本来就要靠局域网 |
| 智能插座断电再上电 | 粗暴,伤硬盘;且断电后 BIOS 需要设"来电自启",很多主板不支持 |
| 向日葵/TeamViewer 的开机棒 | 要额外硬件,且绑定他们家生态 |
| 各类付费内网穿透 | 能用,但开机指令最终还是要落到局域网里的一台机器上 |
核心结论:开机指令必须由局域网内的设备发出,所以那台 24h 在线的设备是绕不开的,既然如此就让它顺便把关机也管了。
-
网卡开启 WOL 设备管理器 → 网络适配器 → 属性 → 高级 →
Wake on Magic Packet/唤醒魔数包= 启用 同一窗口 → 电源管理 → 勾选「允许此设备唤醒计算机」 -
BIOS 关闭 ErP/EuP 这个选项打开后,关机时网卡彻底断电,WOL 必然失效。
-
关掉 Windows 快速启动(关键,见踩坑第 3 条) 控制面板 → 电源选项 → 选择电源按钮的功能 → 更改当前不可用的设置 → 取消勾选「启用快速启动」
-
装 HASS.Agent 并启用
Shutdown命令 它会在 HA 里生成一个button.xxx_shutdown实体,这就是我们的关机入口。 HASS.Agent 走 MQTT 与 HA 通信,机器关机后它自己会掉线,正好可以作为"已关机"的佐证。
需要在 configuration.yaml 里加几段配置(见第五节),改完重启一次 HA。
# configuration.yaml
wake_on_lan:
switch:
- platform: wake_on_lan
name: "电脑电源"
mac: "AA:BB:CC:DD:EE:FF" # 目标机网卡 MAC
host: 192.168.1.100 # 目标机局域网 IP重启后自动出现 button.wake_on_lan_xx_xx_...(按下即发魔术包)和 switch.pc。
建议用 button,语义清晰,也不会像 switch 那样出现"状态和实际不符"的困惑——
wake_on_lan 的 switch 是 assumed_state,它的 on/off 只代表"我按过",不代表机器真实状态。
两条路,选一条:
方案 A:HA ping 集成(HA 与目标机同网段时最简单)
binary_sensor:
- platform: ping
host: 192.168.1.100
name: "电脑在线"
count: 2
scan_interval: 30方案 B:MQTT 遗嘱消息(跨网段、或 ping 被防火墙挡时用)
目标机上的客户端连接 broker 时设置 LWT:
topic: pc/status
payload: offline # 遗嘱:客户端异常掉线时 broker 自动发出
连上后主动 publish online。HA 侧:
mqtt:
binary_sensor:
- name: "电脑在线"
state_topic: "pc/status"
payload_on: "online"
payload_off: "offline"
device_class: connectivity如果你用了 HASS.Agent,它自带一批状态传感器,机器关机后这些实体统一变
unavailable,直接拿其中一个(比如电源状态)当判据也行。
用一个辅助布尔把"开/关"收敛成一个动作,后面写脚本、接语音助手、做卡片都方便。
input_boolean:
pc_power:
name: 电脑
icon: mdi:desktop-tower
automation:
# 翻上去 → 开机
- alias: "电脑开机"
id: pc_wake
triggers:
- trigger: state
entity_id: input_boolean.pc_power
from: "off"
to: "on"
actions:
- action: button.press
target:
entity_id: button.pc_wake_on_lan # 改成你自己的实体名
mode: single
# 翻下来 → 关机
- alias: "电脑关机"
id: pc_shutdown
triggers:
- trigger: state
entity_id: input_boolean.pc_power
from: "on"
to: "off"
actions:
- action: button.press
target:
entity_id: button.pc_shutdown # HASS.Agent 的关机按钮
mode: single
# 状态同步:机器起来了,把总开关扶正
- alias: "电脑开机检测"
id: pc_detect_on
triggers:
- trigger: state
entity_id: binary_sensor.pc_online
from: ["unavailable", "unknown", "off"]
to: "on"
actions:
- action: input_boolean.turn_on
target:
entity_id: input_boolean.pc_power
mode: single
# 状态同步:机器关了,把总开关放平
- alias: "电脑关机检测"
id: pc_detect_off
triggers:
- trigger: state
entity_id: binary_sensor.pc_online
from: "on"
to: ["unavailable", "unknown", "off"]
actions:
- action: input_boolean.turn_off
target:
entity_id: input_boolean.pc_power
mode: single注意:
from/to的写法随 HA 版本有变化。较新版本用triggers/actions, 老版本用trigger/action,两者目前都兼容,混用会报错,统一即可。
HA 网页 → 左下角头像 → 安全 → 长期访问令牌 → 创建,复制那串 eyJ...。
脚本需要它来调 REST API。
去 Releases 下载 RemotePower.exe,和 config.ini 放同一目录,双击运行。
git clone https://github.com/Z2549/RemotePower.git
cd RemotePower
pip install pyinstaller # 只有打包时才需要
python main.py # 直接运行界面
bash build.sh # 打成单文件 exe需要 Python 3.10+,且必须带 tkinter(Windows 官方安装包默认带;
某些精简版/Store 版没有,会报 No module named 'tkinter')。
点界面「设置」,填这几项就够:
| 字段 | 填什么 |
|---|---|
| 目标机 IP | 局域网 IP 或虚拟组网 IP |
| 目标机 MAC | 网卡物理地址,WOL 用 |
| HA 地址 | http://192.168.1.10:8123 |
| HA 令牌 | 上一步拿到的 eyJ... |
| 状态实体 | binary_sensor.pc_online |
| 开关实体 | input_boolean.pc_power |
| 开机按钮 | button.pc_wake_on_lan(可选,留空则用 send_magic_packet) |
| 关机按钮 | button.pc_shutdown(可选) |
填完点「自检」,全绿就可以用了。
[OK ] 目标机地址 192.168.1.100
[OK ] 目标机 MAC AA:BB:CC:DD:EE:FF
[OK ] HA 连通 + 令牌 http://192.168.1.10:8123 -> HTTP 200,实体 141 个
[OK ] wake_on_lan 服务 可用
[OK ] mqtt.publish 服务 可用
[OK ] 状态实体 binary_sensor.pc_online = off → 关机
[OK ] 总开关 input_boolean.pc_power = off
[OK ] 目标机当前状态 离线
界面点按钮,或者命令行:
on.bat :: 开机
off.bat :: 关机
status.bat :: 查状态(在线退出码 0,离线 1,可被其它脚本调用)
check.bat :: 自检也可以直接传参给 exe:RemotePower.exe on|off|toggle|status|check|discover。
发完指令不是就完事了——脚本会轮询状态实体,确认机器真的起来了 / 真的关掉了才返回成功。
这一节是本文最值钱的部分,都是实测踩出来的。
如果你的机器通过 ZeroTier / 节点小宝 / 蒲公英 这类虚拟组网访问, 别用 ping 判断目标机是否开机。
实测:目标机明明已经关机,
ping 192.168.1.100 → TTL=64(显示通!)
端口 22 → CONNECT 成功
端口 445 → CONNECT 成功
端口 3389 → CONNECT 成功
原因是虚拟网卡驱动在本地就把握手回给你了,包根本没到对端。 后果很直接:关机动作用 ping 判断"它已经离线了,不用发指令",于是直接跳过, 机器永远关不掉。
正确做法:状态一律以 HA 实体为准(HA 在真实局域网里,看到的才是真的)。
本工具里 power_entity 就是干这个的,ping 只作最后的兜底。
怎么验证自己是不是中招了:在目标机确定关机的状态下,从你这台机器
ping 它一次、telnet IP 3389 一次。能通就说明你的判定逻辑必须换。
网上不少老教程写 wake_on_lan.turn_on,那是早期版本。现在叫:
service: wake_on_lan.send_magic_packet
data:
mac: "AA:BB:CC:DD:EE:FF"调用前可以在 开发者工具 → 服务 里搜一下,确认服务名和参数。
Win10/11 默认开启"快速启动",它的本质是关机时进休眠——网卡跟着断电, 魔术包收不到。表现是:关机前一切正常,关一次之后就再也唤不醒了。
关掉它:控制面板 → 电源选项 → 选择电源按钮的功能 → 更改当前不可用的设置 → 取消勾选。
顺带一个副作用:快速启动状态下,机器"关机"了但网卡还有电、系统半休眠, 状态判定也会变得很暧昧。
桥接网络下,容器发出的广播包出不了 docker0 网桥,send_magic_packet 会"成功"
但机器纹丝不动。
# docker-compose.yml
services:
homeassistant:
network_mode: host用 HASS.Agent 的按钮作关机入口,意味着它挂了你就关不了机。
同理,那个 button.xxx_shutdown 在目标机关机后必然是 unavailable——
这既是关机成功的证据,也是下次开机时"按钮不可用"的隐患。
判断方法:开机后看这个按钮有没有从 unavailable 变成有时间戳。变了说明 Agent 上线了。
| 现象 | 先查什么 |
|---|---|
| 按了开机,机器不动 | 看 HA 的日志里 button.press 有没有触发;再确认 HA 是否 host 网络;最后查 BIOS 的 ErP |
| 开机成功但状态一直显示离线 | power_entity 填错,或者该实体没有及时更新;用 RemotePower.exe discover 找候选 |
| 关机没反应 | 目标机上 HASS.Agent 是否在跑;button.xxx_shutdown 是不是 unavailable |
| 关机后马上又自己开了 | 状态同步自动化互相打架,检查 from/to 条件 |
自检报 mqtt/publish not found |
HA 没装 MQTT 集成,或者 broker 没连上 |
提示 No module named 'tkinter' |
换用 python.org 的官方安装包(Store 版没有 tkinter) |
RemotePower.exe 单文件可执行(Windows)
RemotePower.bat 启动界面
on.bat / off.bat / status.bat / check.bat
main.py 入口:有参数走 CLI,无参数开 GUI
core.py 配置 / WOL / HA REST / 极简 MQTT 客户端 / 自检
gui.py tkinter 界面(深色)
config.example.ini 配置模板
build.sh / build.bat 打包脚本
- 零第三方依赖:HA 用
urllib走 REST,MQTT 手写 3.1.1 的 CONNECT/PUBLISH(QoS0), 不需要requests、paho-mqtt。好处是打包体积小、不会有依赖冲突。 - 通道降级:开机 6 条、关机 5 条,前一条失败自动试下一条,全失败才报错。
- 确认式操作:发出指令后轮询
power_entity,确认状态真的翻转了才算成功, 不是"消息队列里塞进去就完事"。 - 配置跟 exe 走:
config.ini放在 exe 同目录,扔 U 盘换机器也能用。
配好之后可以让小爱同学接管:
「小爱同学,打开电脑」
通过巴法云把 HA 实体桥接到米家,再交给小爱语音控制。
完整步骤(含版本坑和设备类型对照表)见 → docs/小爱同学接入.md
MIT