WOL远程开机——通过ESP8266+blinker(点灯)平台实现
之前疫情现在家里,无聊时改装家里的吸顶灯入网时,寻找了各种物联网平台,最终找到了blinker(点灯)这个物联网平台,APP很简洁,同时提供方便的API接口,非常适于DIY。
然后就是这次的想法,开学后已经搞好了Teamview远程连接自己的实验室电脑,使自己在宿舍也能科(hua)研(shui),但又因为实验室电脑总是开着,感觉不舒服(毕竟是自己配的机子,不舍得一直烧着)。于是想着怎么远程开关机,淘宝上的向日葵开机棒一个108,看了看原理,发现身为一个电子专业的科研狗,买了就是交智商税,刚好想到了用前面提到的平台,就可以实现远程开机,最后成本就8块钱(或者不要钱,我的ESP8266是本科玩剩下的,用不完就送学弟了)。
说明
本方法适合没公网IP的、没自己服务器的、没高级路由器的三无玩家,有以上几个的也可以这么搞,但没必要,毕竟(教程一堆):
宽带是公网IP的直接走内网映射有腾讯云、阿里云服务器的直接走转发有高级路由器的(带WOL功能)直接设置
但是如果图方便也可以
预备知识
计算机网络基本知识C语言基本知识Arduino编程经验(没有也行)(如果是电子专业的,肯定没啥障碍)
所需材料和前提
前提
自己的电脑支持WOL连着网的路由器(没有上面两个前提的可以直接放弃)
材料
手机APP(blinker,Android & IOS 平台都有)ESP8266模块一个调试下载工具
Arduino IDE平台(编译用)USB转TTL模块(下载用)原理
如果有上述提到的预备知识,则整体原理会非常简单,一句话概括就是手机APP端发送MQTT包到ESP8266,ESP8266转发WOL的UDP包到本地子网。
WOL
WOL(Wake On LAN)局域网唤醒,顾名思义,是一种在局域网内唤醒PC的一种技术。其主要原理是向本地子网内的机器广播一个包含有目标机器网卡MAC地址的一个UDP包(WOL魔术包),所有接收到的机器解析包中的MAC地址,匹配成功的网卡发送对应命令,开启电脑。
Blinker平台
Blinker平台简介其官网有具体的介绍(链接在这),在此就大致说明一下本方法所用到的原理即可。
大致原理即如图所示,在局域网内网中,手机客户端直接通过局域网与ESP8266通讯,ESP8266接收到指令后进行WOL包的广播发送,在非局域网的远程连接中,ESP8266与Blinker服务器连接,同时手机客户端向Blinker服务器发送相关指令后,服务器转发给远端的ESP8266后,ESP8266发送WOL包唤醒电脑。
步骤
STEP1:设置WOL(实现内网唤醒)
WOL在BIOS中设置,具体的机器需要具体设置,就是在BIOS中打开一个选项开关,具体步骤自己在BIOS中找,我的电脑的设置如下:
其次就是在Windows中设置网卡的步骤,设置步骤如下:
首先在设备管理器中找到自己的以太网卡,找到连网线的那个网卡,进行如下操作:
然后继续在此页面下进行已下操作:
最后在网络和共享中心中查看自己网卡的MAC地址和IP地址:
全部设置正确后,便可以在本地局域网下进行设备唤醒了。
iOS下的Wolow软件可以进行测试,在手机连接路由器后(手机,电脑在同一个子网下,同时路由器没有开启AP隔离功能(一般都不开启)),进入对应设置,点击唤醒电脑就可以唤醒了。
注:最好在路由器中设置PC的IP与MAC绑定,方便后续的开机状态检查功能拓展,若不设置此项,开机功能可以用,但是可能无法进行设备开启状态检查!!!
Wolow软件设置如下:
首先添加新设备,界面如下:
接下来按照提示进行相关设置的填写,界面如下:
设置完成后进行测试,若PC没能启动检查是否有设置错误的地方,直到测试成功唤醒。
STEP2:ESP8266程序编写 + Blinker设置(实现外网唤醒)
先贴程序,对着程序进行解释:
/*** 本项目简单的利用了blinker的Button例程,在客户端按下按键后,* 通过MQTT通知ESP8266触发按键处理函数,按键处理函数主要负责* 发送WOL的UDP魔术包,WOL魔术包格式如下* FF FF FF FF FF FF ( XX XX XX XX XX XX (网卡的MAC地址)) x 16* 包的总大小为 6+6*16 = 102 Byte */#define BLINKER_WIFI#include <Blinker.h>//对应客户端的秘钥char auth[] = "************";//WIFI SSIDchar ssid[] = "XXXX";//WIFI Passwordchar pswd[] = "XXXX";#define BUTTON_1 "OPEN"WiFiUDP Udp;//网卡的IP地址const IPAddress remote_ip(192, 168, 0, 1);//根据自己的路由器选择子网段的广播地址#define BROADCAST_ADD "192.168.1.255"//网卡唤醒端口(一般为9或7,可以在BIOS中查看)#define REMOTEPORT 9//ESP8266端口,随便填一个,也填成9#define LOCALPORT 9//网卡的MAC地址 6个字节 char NETCARD_MAC[6] = {0xAA,0xAA,0xAA,0xAA,0xAA,0xAA};//WOL包char WOL_Buffer[102];//调试开关//#define WOL_DEBUG//WOL魔术包初始化void WOL_packet_init(){int i,j;for(i=0;i<6;i++){WOL_Buffer[i] = 0xFF;}for(i=1;i<17;i++){for(j=0;j<6;j++){WOL_Buffer[i*6 + j] = NETCARD_MAC[j];}}#ifdef WOL_DEBUGSerial.printf("The WOL packet is :\n");for(i=0;i<102;i++){Serial.printf("%x ",WOL_Buffer[i]);}#endif}void WOL_packet_transfer(){#ifdef WOL_DEBUGSerial.printf("NOW is send WOL packet!\n");#endifUdp.beginPacket(BROADCAST_ADD, REMOTEPORT);Udp.write(WOL_Buffer);Udp.endPacket();}BlinkerButton Button1(BUTTON_1);void button1_callback(const String & state){BLINKER_LOG("get button state: ", state);if (state == BLINKER_CMD_BUTTON_TAP) {BLINKER_LOG("Button tap!");WOL_packet_transfer();BLINKER_LOG("WOL Packet Transfer Completed!");}else {BLINKER_LOG("Get user setting: ", state);}}void dataRead(const String & data){BLINKER_LOG("Blinker readString: ", data);Blinker.vibrate();uint32_t BlinkerTime = millis();Blinker.print("millis", BlinkerTime);}void setup(){Serial.begin(115200);BLINKER_DEBUG.stream(Serial);Blinker.begin(auth, ssid, pswd);Blinker.attachData(dataRead);Button1.attach(button1_callback);Udp.begin(LOCALPORT);WOL_packet_init();}void loop(){Blinker.run();#ifdef WOL_DEBUGif((Serial.read() == 0x96) || digitalRead(0) == LOW){WOL_packet_transfer();while(digitalRead(0) == LOW){}}#endif}
(1)程序设置
上述程序中,基本功能已经编写好,不想加新东西的话只需要设置以下几项:
客户端相关设置(两项):
设备注册使用:
//对应客户端的秘钥char auth[] = "************";
客户端里的按键的名字,注册按键处理回调函数使用。
#define BUTTON_1 "OPEN"
路由器相关设置(两项):
路由器SSID:
//WIFI SSIDchar ssid[] = "XXXX";
路由器密码:
//WIFI Passwordchar pswd[] = "XXXX";
路由器子网广播地址,将路由器网关地址最后换成255即就是广播地址
//根据自己的路由器选择子网段的广播地址#define BROADCAST_ADD "192.168.1.255"
PC端相关设置(两项):
网卡端口号,一般为7或者9,之前Wolow软件测试用到过。
//网卡唤醒端口(一般为9或7,可以在BIOS中查看)#define REMOTEPORT 9
PC网卡的MAC地址,之前测试用到过。
//网卡的MAC地址 6个字节 char NETCARD_MAC[6] = {0xAA,0xAA,0xAA,0xAA,0xAA,0xAA};
除了客户端相关的两项设置目前无法填写之外,其余的内容在之前的步骤中已经出现过,可以直接填写。
(2)客户端APP设置
首先打开Blinker的APP,没注册的先注册,然后开始设备申请流程:
Step1:添加设备,选择Arduino设备
Step2:选择WIFI接入
Step3:得到设备秘钥,此秘钥对应着程序中的秘钥,直接复制进程序中即可。
Step4:返回主界面,点击进入申请号的设备中
Step5:点击右上角的编辑按键,进入编辑界面,然后添加一个按键,点击出现的按键进入按键设置中
Step6:在按键的基础设置中,首先设置数据键名,此键名为程序中客户端设置的第二个需要填写的项,将此项填入程序中,接着选择按键类型为普通按键即可,其余项目可以不用在意。设置完后保存,退出编辑界面。
Step7:完成APP设置后回到设备主界面,如下:
至此,已经完成相关客户端的相关项设置。
STEP3:程序烧写
将前两步的相关设置填写入程序中,打开Arduino IDE进行程序烧写,需要提前设置IDE的环境,这里就不多讲了,Blinker的开发说明中有非常详细的安装操作步骤(连接在这),完成后点击编译下载进ESP8266模块中(使用IDE下载或使用官方的下载都行,都是通过串口下载,这个也就不多说了,毕竟网上关于ESP8266的资料漫天飞)。
下载完成后,重新启动模块,等待模块连接WIFI成功,同时,在手机客户端可以看见之前的设备从离线状态变为在线状态,点击进入设备,点击按键(此时手机在内外网均可),不出意外,则PC成功启动。
后续拓展功能
Ping功能添加
利用ESP8266去Ping电脑,在开机后,若可以Ping通,则证明已经开机成功。Ping时需要注意的是需要在开机后等待一段时间在去Ping,可以在APP中再定义一组按键来实现状态查询功能, 在状态检测按键按下后,ESP8266开始Ping主机IP,Ping通则利用Blinker的消息组件进行状态返回。
已经测试成功,下面贴出完整的代码:
#define BLINKER_WIFI#include <Blinker.h>#include <ESP8266Ping.h>//对应客户端的秘钥char auth[] = "XXXXXX";//WIFI SSIDchar ssid[] = "XXXXXX";//WIFI Passwordchar pswd[] = "XXXXXX";#define BUTTON_1 "OPEN"#define BUTTON_2 "PC-Status"WiFiUDP Udp;//根据自己的路由器选择子网段的广播地址#define BROADCAST_ADD "192.168.XXX.255"//网卡唤醒端口(一般为9,可以在BIOS中查看)#define REMOTEPORT 9//PC端的IP地址(需要在路由器端进行MAC和IP绑定)const IPAddress remote_ip(192, 168, XXX, XXX);//本地UDP端口#define LOCALPORT 9//网卡的MAC地址 6个字节 char NETCARD_MAC[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};//WOL包char WOL_Buffer[102];//WOL包发送完成标志int complete_flag = 0;//ping计数int ping_num = 0;//WOL魔术包初始化void WOL_packet_init(){int i,j;for(i=0;i<6;i++){WOL_Buffer[i] = 0xFF;}for(i=1;i<17;i++){for(j=0;j<6;j++){WOL_Buffer[i*6 + j] = NETCARD_MAC[j];}}#ifdef WOL_DEBUGSerial.printf("The WOL packet is :\n");for(i=0;i<102;i++){Serial.printf("%x ",WOL_Buffer[i]);}#endif}void WOL_packet_transfer(){#ifdef WOL_DEBUGSerial.printf("NOW is send WOL packet!\n");#endifUdp.beginPacket(BROADCAST_ADD, REMOTEPORT);Udp.write(WOL_Buffer);Udp.endPacket();}BlinkerButton Button1(BUTTON_1);void button1_callback(const String & state){BLINKER_LOG("get button1 state: ", state);if (state == BLINKER_CMD_BUTTON_TAP) {BLINKER_LOG("Button1 tap!");WOL_packet_transfer();BLINKER_LOG("WOL Packet Transfer Completed!");complete_flag = 1;Blinker.notify("!Opening... Plase wait a moment");}else {BLINKER_LOG("Get user setting: ", state);}}BlinkerButton Button2(BUTTON_2);void button2_callback(const String & state){BLINKER_LOG("get button2 state: ", state);if (state == BLINKER_CMD_BUTTON_TAP) {BLINKER_LOG("Button2 tap!");if(complete_flag){if(Ping.ping(remote_ip)){Blinker.notify("!PC Open Successful!");ping_num = 0;complete_flag = 0;}else{Blinker.notify("!Opening... Plase wait a moment");ping_num++;if(ping_num > 4){ping_num = 0;complete_flag = 0;Blinker.print("Open Failed,Plase tap button again!");Blinker.notify("!Open Failed,Plase tap button again");}}}else{Blinker.notify("!Plase tap button again!");}}else {BLINKER_LOG("Get user setting: ", state);}}void dataRead(const String & data){BLINKER_LOG("Blinker readString: ", data);Blinker.vibrate();uint32_t BlinkerTime = millis();Blinker.print("millis", BlinkerTime);}void setup(){Serial.begin(115200);BLINKER_DEBUG.stream(Serial);Blinker.begin(auth, ssid, pswd);Blinker.attachData(dataRead);Button1.attach(button1_callback);Button2.attach(button2_callback);Udp.begin(LOCALPORT);WOL_packet_init();}void loop(){Blinker.run();}
APP界面如下:
补充说明
这只是个简单的开机模块,至于远程开机有什么用,对于我来说就是配合Teamview实现在宿舍科研,远程跑个仿真啥的非常方便,不用的话可以在power shell中利用shutdown -s指令进行关机,减少机子的空耗时间,增加寿命。这只是个基础的版本,后面可以添加各种功能进行DIY,看各位发挥了!