赞
踩
小爱同学应该已经是家喻户晓的了,现在一直用来控制家里的家电。于是乎突发奇想想用来操作电脑上的软件会怎么样,比如打开某个程序不用再去寻找,直接喊小爱同学打开,真的很方便,现在先来实现一个最简单的,用小爱同学来控制电脑关机。当然只是关机,开机还需要通过设置主板来实现,等后续研究成功了再记录吧。
其实很简单,只要通过小爱同学给电脑发送一条指令,然后电脑收到此指令后就运行shutdown -s -t 10
指令,其中10是关机的时间,单位为秒。要想立即关机可以使用shutdown -h
.取消关机使用shutdown -a
。通过以上即可指令即可自由的控制电脑什么时候关机。
现在问题是要怎样让电脑收到小爱同学的指令呢,通过百度查到可以使用巴法云,操作及其简单。
https://bemfa.com/通过以上地址进入巴法云官网,点击注册账号后登录,然后进入控制台,可以看到以下页面:
注意你的私匙
是控制电脑的关键
通过官方接入文档可以看到巴法云支持多种接入方式,再Winform中最简单的就是通过TCP方式接入。
接入前需要先点击新建一个主题,这里我们创建一个TCP创客云的主题,命名为Computer001
.
这里需要注意接入米家需要注意主题的命名,官方文档介绍如下:
巴法云物联网平台默认接入米家,仅支持以下类型的设备:插座、灯泡、风扇、传感器、空调、开关、窗帘。
用户可以自主选择是否接入米家,根据主题名字判定。
当主题名字后三位是001时为插座设备。
当主题名字后三位是002时为灯泡设备。
当主题名字后三位是003时为风扇设备。
当主题名字后三位是004时为传感器设备。
当主题名字后三位是005时为空调设备。
当主题名字后三位是006时为开关设备。
当主题名字后三位是009时为窗帘设备。
我这里使用了001,小爱同学可以传送回来的指令为off
或者no
,代表插座的开关。
创建主题后最好更改一下昵称,点一下你主题的昵称的位置即可修改。这是昵称是接入米家后用来控制的设备名称。
下载米家APP,登录后在下方找到我的
,点击其他平台设备
点击添加,然后找到巴法
绑定后会显示在其他设备的列表中,并且点击进去会显示刚刚创建的主题
现在设备已经接入米家了,但是如果现在叫小爱同学控制,小爱同学会说不在线。此时我们可以使用串口工具测试一下是否可以接收到指令。
按照官方教程,先下载串口调试工具
打开工具后界面如下:
端口好为TCPClient
,远程地址更改为·bemfa.com
,端口为8344
,然后点击连接。现在需要订阅你创建的那个主题,也就是让你的设备处于在线状态。
在左下角的文本框中输入
cmd=1&uid=xxxxxxxxxxxxxxxxxxxxxxx&topic=xxx1,xxx2,xxx3,xxx4\r\n
注意更改uid与topic,uid为你的私匙,topic为主题名称,多个主题使用逗号相隔。记得\r\n
需要带上。
输入 指令点击发送,就会返回如下命令:
同时在巴法的控制台可以看到你的主题订阅数变为1
现在可以对着小爱同学说小爱同学 关闭电脑
,在调试界面会出现如下返回
至此你的小爱同学已经连接到巴法云了,接下来开始写代码处理这个信息。
创建一个Winform程序,窗口如下:
在load方法中赋值uid与topic
Form1_Load
private void Form1_Load(object sender, EventArgs e)
{
textBox1.Text = uid;
textBox2.Text = "computer001";
button1_Click(sender, e);
}
button1_Click
方法为点击按钮的事件。
主要方法代码如下:
// 连接巴法云TCP服务器 private void TcpL() { IPHostEntry hostEntry = Dns.GetHostEntry("bemfa.com"); IPEndPoint ipEndPoint = new IPEndPoint(hostEntry.AddressList[0], 8344); //IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse("192.168.31.114"), 777); try { tcpClient.Connect(ipEndPoint); Console.WriteLine("Connected"); ShowMsg("Connect Success!"); Thread c_thread = new Thread(Received); c_thread.IsBackground = true; c_thread.Start(); Send($"cmd=1&uid={textBox1.Text}&topic={textBox2.Text}\r\n"); } catch (Exception ex) { ShowMsg(ex.ToString()); } }
/// <summary> /// 接收信息 /// </summary> private void Received() { NetworkStream networkStream = tcpClient.GetStream(); EndPoint remoteEndPoint = tcpClient.Client.RemoteEndPoint; byte[] datas = new byte[1024]; while (true) { if (networkStream.DataAvailable) { int len = networkStream.Read(datas, 0, 1024); string v = Encoding.UTF8.GetString(datas); string cmd = ParseQueryString(v, "cmd"); string msg = ParseQueryString(v, "msg"); if (cmd.Equals("2") && msg.IndexOf("off") == 0) { //ShowMsg("电脑将于3s后关闭!"); Process proc = new Process(); proc.StartInfo.FileName = "cmd.exe"; // 启动命令行程序 proc.StartInfo.UseShellExecute = false; // 不使用Shell来执行,用程序来执行 proc.StartInfo.RedirectStandardError = true; // 重定向标准输入输出 proc.StartInfo.RedirectStandardInput = true; proc.StartInfo.RedirectStandardOutput = true; proc.StartInfo.CreateNoWindow = true; // 执行时不创建新窗口 proc.Start(); string commandLine; //if (isCancel) // commandLine = @"shutdown /a"; // 停止关机 commandLine = @"shutdown /s /t 0"; // 立即关机 proc.StandardInput.WriteLine(commandLine); return; } ShowMsg(Encoding.UTF8.GetString(datas)); //Console.WriteLine($"From:{remoteEndPoint}:Received ({len})"); } Thread.Sleep(1); } }
/// <summary>
/// 发送信息
/// </summary>
/// <param name="msg"></param>
private void Send(string msg)
{
NetworkStream networkStream = tcpClient.GetStream();
EndPoint remoteEndPoint = tcpClient.Client.RemoteEndPoint;
byte[] datas = new byte[1024];
datas = Encoding.ASCII.GetBytes(msg);
networkStream.Write(datas, 0, datas.Length);
}
通过多次测试发现,如果一分钟没有向服务器发送指定,那么就会自动断开连接。这里添加一段代码每隔30s向服务器请求一段数据。
public void StartCommIdle() { //定时器配置 Thread c_thread = new Thread(Heartbeat); c_thread.IsBackground = true; c_thread.Start(); } public void Heartbeat() { try { while (true) { Send($"ping\r\n"); Thread.Sleep(30000); } } catch (Exception) { TcpL(); } }
要将StartCommIdle
方法加载Tcp
方法后面
要想随时接收小爱同学的指令就需要一直打开此程序,如果电脑窗口多了这个界面还不能关掉就很烦,所以再添加一段代码用于将程序后台运行并将图标显示在任务栏中。
在winform的组件中添加notifyIcon
找到Icon
属性设置图标
如果想再显示主界面可以添加菜单栏选项
添加contextMenuStrip
组件,并设置他们的方法。
找到Form_Closing属性,
绑定如下方法,这样点击关闭按钮后程序不会退出,而是再后台运行。
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
e.Cancel = true;
this.Visible = false;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
如果想要关闭则在菜单栏中添加关闭方法:
private void smi_exit_Click(object sender, EventArgs e)
{
DialogResult result = MessageBox.Show("你确定要关闭吗!", "提示信息", MessageBoxButtons.OKCancel, MessageBoxIcon.Information);
if (result == DialogResult.OK)
{
// 关闭所有的线程
this.Dispose();
this.Close();
}
}
显示主界面方法:
private void Form1_FormShow(object sender, EventArgs e)
{
this.Visible = true;
}
至此,只要对着小爱同学说关闭电脑,电脑会马上关机。
以下为完整代码,供参考,注意uid需要设置为自己的私钥。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Net.Sockets; using System.Net; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using static System.Windows.Forms.VisualStyles.VisualStyleElement; using System.Diagnostics; namespace TCPShutdown { public partial class Form1 : Form { private TcpClient tcpClient = new TcpClient(); private string uid = ""; public Form1() { InitializeComponent(); this.Hide(); } private void TcpL() { IPHostEntry hostEntry = Dns.GetHostEntry("bemfa.com"); IPEndPoint ipEndPoint = new IPEndPoint(hostEntry.AddressList[0], 8344); //IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse("192.168.31.114"), 777); try { tcpClient.Connect(ipEndPoint); Console.WriteLine("Connected"); ShowMsg("Connect Success!"); Thread c_thread = new Thread(Received); c_thread.IsBackground = true; c_thread.Start(); Send($"cmd=1&uid={textBox1.Text}&topic={textBox2.Text}\r\n"); StartCommIdle(); } catch (Exception ex) { ShowMsg(ex.ToString()); } } public void StartCommIdle() { //定时器配置 Thread c_thread = new Thread(Heartbeat); c_thread.IsBackground = true; c_thread.Start(); } public void Heartbeat() { try { while (true) { Send($"ping\r\n"); Thread.Sleep(30000); } } catch (Exception) { TcpL(); } } /// <summary> /// 接收信息 /// </summary> private void Received() { NetworkStream networkStream = tcpClient.GetStream(); EndPoint remoteEndPoint = tcpClient.Client.RemoteEndPoint; byte[] datas = new byte[1024]; while (true) { if (networkStream.DataAvailable) { int len = networkStream.Read(datas, 0, 1024); string v = Encoding.UTF8.GetString(datas); string cmd = ParseQueryString(v, "cmd"); string msg = ParseQueryString(v, "msg"); if (cmd.Equals("2") && msg.IndexOf("off") == 0) { ShowMsg("电脑将于3s后关闭!"); Process proc = new Process(); proc.StartInfo.FileName = "cmd.exe"; // 启动命令行程序 proc.StartInfo.UseShellExecute = false; // 不使用Shell来执行,用程序来执行 proc.StartInfo.RedirectStandardError = true; // 重定向标准输入输出 proc.StartInfo.RedirectStandardInput = true; proc.StartInfo.RedirectStandardOutput = true; proc.StartInfo.CreateNoWindow = true; // 执行时不创建新窗口 proc.Start(); string commandLine; //if (isCancel) // commandLine = @"shutdown /a"; commandLine = @"shutdown /s /t 0"; proc.StandardInput.WriteLine(commandLine); return; } ShowMsg(Encoding.UTF8.GetString(datas)); //Console.WriteLine($"From:{remoteEndPoint}:Received ({len})"); } Thread.Sleep(1); } } /// <summary> /// 发送信息 /// </summary> /// <param name="msg"></param> private void Send(string msg) { NetworkStream networkStream = tcpClient.GetStream(); EndPoint remoteEndPoint = tcpClient.Client.RemoteEndPoint; byte[] datas = new byte[1024]; datas = Encoding.ASCII.GetBytes(msg); networkStream.Write(datas, 0, datas.Length); } void ShowMsg(string str) { this.Invoke(new Action(() => { richTextBox1.AppendText(str + "\r\n"); })); } void ShowNotice(string str) { this.Invoke(new Action(() => { textBox3.AppendText(str + "\r\n"); })); } private void button1_Click(object sender, EventArgs e) { TcpL(); } private void Form1_Load(object sender, EventArgs e) { textBox1.Text = uid; textBox2.Text = "computer001"; button1_Click(sender, e); } private void smi_exit_Click(object sender, EventArgs e) { DialogResult result = MessageBox.Show("你确定要关闭吗!", "提示信息", MessageBoxButtons.OKCancel, MessageBoxIcon.Information); if (result == DialogResult.OK) { // 关闭所有的线程 this.Dispose(); this.Close(); } } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { try { e.Cancel = true; this.Visible = false; } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void button2_Click(object sender, EventArgs e) { this.Visible = false; //Send($"cmd=7&uid={uid}&type=1\r\n"); } public static string ParseQueryString(string url, string key) { if (string.IsNullOrWhiteSpace(url)) { throw new ArgumentNullException("url"); } //1.去除第一个前导?字符 //var dic = string value = null; Dictionary<string, string> dictionary = url //2.通过&划分各个参数 .Split(new char[] { '&' }, StringSplitOptions.RemoveEmptyEntries) //3.通过=划分参数key和value,且保证只分割第一个=字符 .Select(param => param.Split(new char[] { '=' }, 2, StringSplitOptions.RemoveEmptyEntries)) //4.通过相同的参数key进行分组 .GroupBy(part => part[0], part => part.Length > 1 ? part[1] : string.Empty) //5.将相同key的value以,拼接 .ToDictionary(group => group.Key, group => string.Join(",", group)); dictionary.TryGetValue(key, out value); return value; } private void Form1_FormShow(object sender, EventArgs e) { this.Visible = true; } } }
仅供学习使用,如转发请标明出处,谢谢。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。