使用小爱同学语音控制电脑关机 - Winform C#

news2024/12/23 18:27:55

使用小爱同学语音控制电脑变关机

  • 前言
  • 实现原理
  • 准备
    • 注册巴法云账号
    • 接入巴法云
    • 接入米家
  • 编写程序
    • 连接TCP
    • 接收信息并运行关机指令
    • 发送指令订阅主题
    • 添加心跳机制
    • 后台运行
    • 阻止默认关闭窗口事件
  • 完整代码


前言

小爱同学应该已经是家喻户晓的了,现在一直用来控制家里的家电。于是乎突发奇想想用来操作电脑上的软件会怎么样,比如打开某个程序不用再去寻找,直接喊小爱同学打开,真的很方便,现在先来实现一个最简单的,用小爱同学来控制电脑关机。当然只是关机,开机还需要通过设置主板来实现,等后续研究成功了再记录吧。

实现原理

其实很简单,只要通过小爱同学给电脑发送一条指令,然后电脑收到此指令后就运行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
在这里插入图片描述

现在可以对着小爱同学说小爱同学 关闭电脑,在调试界面会出现如下返回

在这里插入图片描述
至此你的小爱同学已经连接到巴法云了,接下来开始写代码处理这个信息。

编写程序

连接TCP

创建一个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;
        }
    }
}

仅供学习使用,如转发请标明出处,谢谢。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/87262.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

selenium + python自动化测试环境搭建(有手就行)

selenium 是一个web的自动化测试工具&#xff0c;不少学习功能自动化的同学开始首选selenium &#xff0c;相因为它相比QTP有诸多有点&#xff1a; 免费&#xff0c;也不用再为破解QTP而大伤脑筋 小巧&#xff0c;对于不同的语言它只是一个包而已&#xff0c;而QTP需要下载安装…

时序预测 | MATLAB实现PSO-SVM粒子群优化支持向量机时间序列预测

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

LeetCode刷题日记之链表II

1.四数相加II 题目描述 解题思路 1.定义一个哈希Map,其中key存放两数之和&#xff0c;value存放两数和出现的次数。 2.遍历统计出nums1和nums元数相加和出现的次数(ab)。 3.遍历nums3和nums4&#xff0c;并求和(cd),统计出(0-(cd))在Map中出现的次数。 4.返回&#xff08;0-(…

央企招聘:中国人民银行2023年度招聘启事

2023年中国外汇交易中心 博士后科研工作站招聘公告 中国外汇交易中心暨全国银行间同业拆借中心&#xff08;以下简称“交易中心”&#xff09;于1994年成立&#xff0c;是中国人民银行直属事业单位&#xff0c;为银行间外汇、货币、债券及其衍生产品提供交易、发行、基准及一线…

如何通过.exe文件控制一台电脑

CVE-2022-21999漏洞 如何实现发送一个.exe文件偷偷控制他人的电脑&#xff1f;这个想法很刑的&#xff0c;所以我只是说明我的实现方式&#xff0c;具体操作建议仅用于hvv等专业领域&#xff0c;请勿以身试法。 首先我们分析一下.exe文件的实际应用场景---windows系统的电脑&am…

11、setoolkit工具 构造钓鱼网站、powershell注入

靶机&#xff1a;192.168.11.105攻击机kail&#xff1a;192.168.11.1061.在kali中启动setoolkitsetoolkit2.利用SET构建钓鱼网站1&#xff09;选择1 Social-Engineering Attacks &#xff08;社会工程学攻击&#xff09;2&#xff09;选择2 Website Attack Vectors &#xff…

Spring Boot 概念、创建和运行 · Spring Boot 的优点 · 启动第一个 Spring Boot · Spring Boot 的注意事项

一、什么是 Spring Boot二、Spring Boot 优点三、Spring Boot 项目创建四、项目目录介绍和运行4.1 运行项目4.2 输出 Hello World五、注意事项5.1 包路径错误5.2 小结&#xff1a;约定大于配置六、总结一、什么是 Spring Boot Spring 的诞生是为了简化 Java 程序的开发的&…

GAMES101-现代计算机图形学入门-闫令琪 课程笔记 - 汇总(上)

一些前言与感慨&#xff1a; 学了再多的AI&#xff0c;终究还是没有办法拒绝计算机图形学的魅力。当初就不该一招不慎&#xff0c;踏入AI的坑。 可惜当年在学校里学计算机图形学的时候&#xff0c;还没有闫令琪这么好的课程&#xff0c;当时学得一知半解&#xff0c;云里雾里…

极市直播回放第106期丨阿里达摩院:兼顾速度与精度的高效目标检测框架DAMO-YOLO

阿里巴巴达摩院智能计算实验室团队设计并开源了一款兼顾速度与精度的目标检测框架DAMO-YOLO&#xff0c;其性能超越了目前的一众YOLO系列方法&#xff0c;在实现精度SOTA的同时&#xff0c;保持了很高的推理速度。DAMO-YOLO是在YOLO框架基础上引入了MAE-NAS、efficient-RepGFPN…

cas:1628790-40-8|脂溶性Cyanine7-COOH|CY7-Carboxylic Acid

cas:1628790-40-8|脂溶性Cyanine7-COOH|CY7-Carboxylic Acid 名称&#xff1a;脂溶性Cyanine7-COOH|CY7-Carboxylic Acid cas:1628790-40-8 英文同义词: Cy7;Colpro;Prothil;R-13615;Cy7-COOH;CY7ACID;Cy7NHS;AY-62022;Cy7,>97%;Sulfo-Cyanine7 中文名称:磺基-CY7羧酸 …

【小甲鱼C语言】课后笔记第一章第四节——数据类型

目录 1、数据类型 2、short 和 long 3. sizeof 运算符 4. signed 和 unsigned 5、课后习题&#xff08;编程题&#xff09; 1、数据类型 在 C 语言里&#xff0c;所谓的数据类型就是坑的大小。我们说变量就是在内存里边挖一个坑&#xff0c;然后给这个坑命名。那么数据类型…

U盘格式化后能恢复数据吗?U盘删除的数据还能恢复吗

U盘格式化后能恢复数据吗&#xff1f;通常情况下&#xff0c;我们U盘里的数据丢失后&#xff0c;它们并没有立即消失&#xff0c;它们只是被系统做了一个标记&#xff0c;将数据存储的位置标记成可写入的状态&#xff0c;只有当新数据写入的时候&#xff0c;这个存储位置才会被…

USB转UART的桥接控制器 国产DPU02能不能软硬件兼容替换CP2102?

DPU02是一个高度集成的USB转UART的桥接控制器&#xff0c;可将RS-232设计更新为USB设计&#xff0c;并简化PCB组件空间。 该DPU02包括了一个USB 2.0全速功能控制器、USB收发器、振荡器、EEPROM和带有完整调制解调控制信号的异步串行数据总线&#xff08;UART&#xff09;控制器…

自动驾驶车辆安全保证机制-Mobileye的RSS模型

自动驾驶汽车(AV)将如何与人类司机安全地共享道路? 成功实现自动驾驶未来的最大威胁之一是对自动驾驶汽车安全驾驶的含义缺乏共识。只有当行业、政府和公众有一个共同的方式来理解和评估自动驾驶汽车(AV)的驾驶技能和安全,他们才会被信任,可以安全地与人类驾驶的车辆一起…

Go1.19.3 数组与切片原理简析

数组 Go语言数组&#xff0c;声明有如下几种方式&#xff1a; var arr1 [10]intarr1[0] 10000var arr2 [10]int{0:0,2:2}var arr3 [...]int{1,2,3}其中arr1只是进行声明&#xff0c;数组在声明时&#xff0c;内存空间已经被开辟过&#xff0c;所以可以赋值。arr2是声明的同…

javafx 编写管理页面 增删改查

注册界面&#xff1a;用户通过输入页面信息&#xff0c;点击注册&#xff0c;将数据存入数据库中。 <Tab text"用户注册"> <content> <AnchorPane minHeight"0.0" minWidth"0.0" prefHeight"761.0" prefWidth"819…

Vue的四个常用选项

文章目录前言一、四大选项简介二、filters&#xff08;过滤器&#xff09;三、computed&#xff08;计算属性&#xff09;四、methods&#xff08;方法&#xff09;五、watch&#xff08;观察&#xff09;总结:前言 本文讲解了vue.js中的四个常用选项&#xff0c;4个参数选项&…

数据结构——归并排序

坚持看完&#xff0c;结尾有思维导图总结 这里写目录标题归并排序的思路归并算法的图解具体程序对性质的分析归并排序的非递归版本总结归并排序的思路 首先第一个问题是&#xff0c;什么是归并排序&#xff1f; 官方的说法: 归并排序&#xff08;MERGE-SORT&#xff09;是建立…

pikachu靶场-7 不安全的文件下载和上传

不安全的文件下载和上传 不安全的文件下载 文件下载&#xff08;unsafedownload&#xff09;漏洞概述 很多网站都会提供文件下载功能&#xff0c;即用户可以通过点击下载链接&#xff0c;下载到链接所对应的文件。 但是&#xff0c;如果文件下载功能设计不当&#xff0c;则…

基于51单片机的数字频率计设计

仿真原理图&#xff1a; 程序运行图&#xff1a; 部分程序&#xff1a; #define LED_GLOBAL 1 #include "led.h" /******************************************************************************************* *函数名称&#xff1a;delay_us(uint us) *函数…