本文将介绍如何使用ESP32硬件制作一个开机棒,通过.Net nanoFramework实现WOL(Wake-on-LAN)功能,发送WOL数据包来唤醒远程计算机。
1. 背景
在之前的文章中,我们介绍了如何使用.Net nanoFramework相关的库来实现一些功能,比如读取传感器数据、控制LED灯、OLED显示等。也介绍了通过.NET实现WOL(Wake-on-LAN)功能,并在NAS或通过ASP.NET进行部署。可以能有的小伙伴没有NAS或者服务器,但是有ESP32硬件,那么我们可以使用ESP32硬件制作一个开机棒,通过发送WOL数据包来唤醒远程计算机。在这篇文章中,我们将介绍如何使用.Net nanoFramework实现WOL(Wake-on-LAN)功能,通过发送WOL数据包来唤醒远程计算机。
相关文章:
- 使用.NET实现WOL唤醒远程开机
- ASP.NET版本WOL服务的使用
- 在NAS上部署.NET版本的WOL远程开机服务
- 快速入门 .NET nanoFramework 开发 ESP32-Pico 应用
- 解决ESP32板载WS2812B LED反色问题及工作状态灯的应用
以上的文章包含了基本的WOL相关实现和介绍以及.Net nanoFramework基础开发知识,如果你对.Net nanoFramework不熟悉,建议先阅读这些文章,可以帮助你更好的读懂本文的内容。
2. 实现方法
在工作状态灯的应用文章中,我们介绍了一个 ProjectImprovWifi
的示例项目,这个示例包含了基本的工作状态灯控制,我们可以基于这个项目框架来快速实现WOL功能。
WOL的实现原理是通过网络发送一个特定的数据包(Magic Packet)到目标计算机的MAC地址,目标计算机就会被唤醒。在.Net nanoFramework中,我们可以使用 nanoFramework.System.Net.Sockets.UdpClient
库来实现UDP数据包的发送。
下面的代码示例演示了如何使用.Net nanoFramework实现WOL功能,这里需要注意的是,因为环境的限制,UdpClient
的使用,以及没有Replace
方法等问题,需要我们对之前.NET的代码进行一些修改:
using System;
using System.Net;
using System.Net.Sockets;
namespace WakeOnLan_ESP32
{
internal class WakeOnLan
{
internal static void Send(string macAddress)
{
byte[] magicPacket = CreateMagicPacket(macAddress);
SendMagicPacket(magicPacket);
}
static byte[] CreateMagicPacket(string macAddress)
{
byte[] macBytes = ParseMacAddress(macAddress);
byte[] magicPacket = new byte[6 + (6 * 16)];
for (int i = 0; i < 6; i++)
{
magicPacket[i] = 0xFF;
}
for (int i = 6; i < magicPacket.Length; i += 6)
{
Array.Copy(macBytes, 0, magicPacket, i, 6);
}
return magicPacket;
}
static byte[] ParseMacAddress(string macAddress)
{
if (macAddress.Length == 17)
{
macAddress = macAddress.Substring(0, 2) + macAddress.Substring(3, 2) + macAddress.Substring(6, 2) + macAddress.Substring(9, 2) + macAddress.Substring(12, 2) + macAddress.Substring(15, 2);
}
if (macAddress.Length != 12)
{
throw new ArgumentException("Invalid MAC address.");
}
byte[] macBytes = new byte[6];
for (int i = 0; i < 6; i++)
{
macBytes[i] = Convert.ToByte(macAddress.Substring(i * 2, 2), 16);
}
return macBytes;
}
static void SendMagicPacket(byte[] magicPacket)
{
UdpClient udpClient = new UdpClient();
udpClient.Connect(IPAddress.Broadcast, 9);
udpClient.Send(magicPacket);
udpClient.Close();
Console.WriteLine("Magic packet sent.");
}
}
}
在这个示例中,我们定义了一个 WakeOnLan
类,其中包含了 Send
方法,用于发送WOL数据包。在 Send
方法中,我们首先调用 CreateMagicPacket
方法创建一个Magic Packet,然后调用 SendMagicPacket
方法发送数据包。
3. 页面设计
完成了核心的唤醒代码后,我们需要让用户输入目标计算机的MAC地址,然后点击按钮发送WOL数据包。这里我们可以使用OLED显示屏来显示提示信息和用户输入的MAC地址。这里可以使用 ESP32 创建一个Web服务器,通过浏览器输入MAC地址,然后发送WOL数据包。
这里我们需要用到nanoFramework.System.Net.Http
库,这个库可以用来创建一个简单的Web服务器,接收用户的输入,然后发送WOL数据包。
string responseString =
"<HTML><HEAD>" +
"<meta name='viewport' content='width=device-width, initial-scale=1'>" +
"<style>" +
"body { font-family: Arial, sans-serif; margin: 20px;text-align: center;}" +
"h2 { color: #333; }" +
"form { margin-top: 20px; }" +
"input[type='text'] { padding: 10px; border: 1px solid #ccc; border-radius:4px 0 0 4px; width: 250px; }" +
"input[type='submit'] { padding: 10px 20px; border: none; border-radius:0 4px 4px 0; background-color: #4CAF50; color: white; cursor: pointer; }" +
"input[type='submit']:hover { background-color: #45a049; }" +
"p { line-height: 1.6; }" +
"a { color: #1E90FF; text-decoration: none; }" +
"a:hover { text-decoration: underline; }" +
"#mac-list { margin: 20px auto; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); width: 100%; max-width: 350px; }" +
"#mac-list ul { list-style-type: none; padding: 0; }" +
"#mac-list li { padding: 5px 0; border-bottom: 1px solid #ccc; }" +
"</style>" +
"</HEAD><BODY>" +
"<h2>ESP32 WakeOnLan</h2>" +
"<p>Click the button to send a Wake On LAN packet.</p>" +
"<form method='get' action='/wol' οnsubmit='return validateAndFormatMac()'>" +
"<input type='text' id='mac' name='mac' value='' />" +
"<input type='submit' value='Wake On LAN' />" +
"</form>" +
"<div id='mac-list'>" +
"<h3>Stored MAC Addresses</h3>" +
"<ul id='list'></ul>" +
"</div>" +
"<script>" +
"function validateAndFormatMac() {" +
" var macInput = document.getElementById('mac');" +
" var mac = macInput.value;" +
" var macRegex = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/;" +
" if (!macRegex.test(mac)) {" +
" alert('Invalid MAC address format. Please use XX:XX:XX:XX:XX:XX or XX-XX-XX-XX-XX-XX.');" +
" return false;" +
" }" +
" mac = mac.replace(/[:-]/g, '');" +
" macInput.value = mac;" +
" storeMac(mac);" +
" return true;" +
"}" +
"function storeMac(mac) {" +
" var macs = JSON.parse(localStorage.getItem('macs')) || [];" +
" macs.push(mac);" +
" localStorage.setItem('macs', JSON.stringify(macs));" +
" displayMacs();" +
"}" +
"function displayMacs() {" +
" var macs = JSON.parse(localStorage.getItem('macs')) || [];" +
" var list = document.getElementById('list');" +
" list.innerHTML = '';" +
" macs.forEach(function(mac) {" +
" var li = document.createElement('li');" +
" var a = document.createElement('a'); " +
" a.href = '/wol?mac=' + mac;" +
" a.textContent = mac;" +
" li.appendChild(a);" +
" list.appendChild(li);" +
" });" +
"}" +
"document.addEventListener('DOMContentLoaded', displayMacs);" +
"</script>" +
"</BODY></HTML>";
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
HttpListener listener = new("http", 80);
listener.Start();
这里的网页内容是硬编码在代码中的,我们可以通过 HttpListener
类来创建一个简单的Web服务器,然后监听用户的输入。用户输入的MAC地址会被存储在本地存储中,然后显示在页面的底部。用户可以点击列表中的MAC地址来发送WOL数据包。
启动服务后,我们简单的使用一个死循环来监听用户的请求,通过判断URL是否包含/wol?mac=
来发送WOL数据包,然后返回一个JSON格式的响应。
while (true)
{
try
{
HttpListenerContext context = listener.GetContext();
var url = context.Request.RawUrl;
HttpListenerResponse response = context.Response;
if (url.StartsWith("/wol?mac="))
{
var macAddress = url.Substring(9);
Console.WriteLine($"WOL packet sent to {macAddress}");
WakeOnLan.Send(macAddress);
// 输出json格式
response.ContentType = "application/json";
var json = System.Text.Encoding.UTF8.GetBytes("{\"status\":\"ok\"}");
response.ContentLength64 = json.Length;
response.OutputStream.Write(json, 0, json.Length);
}
else
{
// 输出默认页面
response.ContentLength64 = buffer.Length;
response.OutputStream.Write(buffer, 0, buffer.Length);
}
context.Response.Close();
Console.WriteLine("Web response sent");
context.Close();
}
catch (Exception ex)
{
Console.WriteLine("* Error getting context: " + ex.Message + "\r\nSack = " + ex.StackTrace);
}
}
4. 使用方法
在完成了代码的编写后,我们可以将代码部署到ESP32上。首次使用需要先完成 Improv 蓝牙配网,这里可以通过"Improv 蓝牙配网"微信小程序或者 Improv 官网来完成。建议是使用小程序,这样可以在配网成功后,可以直接显示ESP32的IP地址。
然后通过浏览器访问ESP32的IP地址,即可看到硬件的 Web 服务,可以在页面上输入MAC地址,然后点击按钮发送WOL数据包。
5. 总结
在这篇文章中,我们介绍了如何使用.Net nanoFramework实现WOL功能,通过发送WOL数据包来唤醒远程计算机。我们首先实现了核心的WOL代码,然后通过Web服务器来接收用户的输入,最后发送WOL数据包。这样可以方便我们通过浏览器来发送WOL数据包,实现远程开机的功能。
文章介绍的相关代码已开源在GitHub,欢迎查看和收藏。希望这篇文章对你有所帮助,如果有任何问题或建议,欢迎在评论区留言。
如果你对ESP32版本的WOL感兴趣,可以关注“桑榆肖物”,回复“网络唤醒”获取完整源码。
Github 主页:https://github.com/sangyuxiaowu?WT.mc_id=DT-MVP-5005195