智能管家(原型)- 语音控制设备

最近研究物联网相关的东西,做了个小原型,称它为智能管家,能用语音控制设备以及手机APP控制设备。

先看看结构图:

功能描述:

  1. 通过语音控制器,说话,比如说出“帮我开灯”,led灯就量,或者说出“把这个灯给关了”,led灯就灭了
  2. 手机APP上有手动开关来控制led灯的亮和灭
  3. 支持全国范围覆盖,既不能局限于家里的LAN

目前为止,用到的设备主要就是ESPDuino。

ESPDuino:WIFI+Arduino

相关:

  1. ESP8266-01/ESP-01虽然很便宜但是用起来很麻烦,所以弃用
  2. Arduino Yun/Tian虽然功能强大,但是太贵700、800的节奏,弃用(不过这2个是带操作系统的,linino,基于openwrt)
  3. ESPDuino: 不带OS,集成WIFI功能,方便还便宜,大概40左右

 分别来介绍下,分为:

  1. OneNet部分
  2. 手机APP部分
  3. 语音控制器部分
  4. ESPDuino执行部分

OneNet部分:

这里我们的主要工作是建立设备,记录下api_key,产品Id这些,并且我们使用的是MQTT协议进行通信(在产品定义中有)(需要新建产品以及新建设备2个步骤)

 

 手机APP部分

由于不会app开发,并且onenet提供了简单的app平台,因此就用onenet的来做,如下,新增一个应用后进入设计app界面:

上图中代表,此时点击 ON button就会下发指令到设备espduino,并且指令为   开灯  字符串, OFF button则为指令  关灯  字符串。

然后保存,需要在手机上看的话,需要安装onenet的app,需要自己找找,最终效果截图:

手机app部分也算完工了,很简陋,但是能控制就好。

语音控制器部分

这个部分分成了2个部分:语音解析文本及命令解析、命令下发;

语音解析文本及命令解析程序:

用的是讯飞语音api,c代码,我是用MFC做了个GUI程序,把demo代码嵌进去,把文本解析成相应的命令,如“开灯”、“关灯”

命令下发程序:

接收MFC发来的命令,比如“开灯”、“关灯”,然后调用onenet的api来下发指令到设备

这部分是用C#做的,因为有很方便的现成的库,很容易的几行代码就搞定

由于MFC比较复杂,这部分的我就截几段我认为关键的代码吧:

 

 MFC代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
static void show_result(char *string, char is_over)
{
    COORD orig, current;
    CONSOLE_SCREEN_BUFFER_INFO info;
    HANDLE w = GetStdHandle(STD_OUTPUT_HANDLE);
    GetConsoleScreenBufferInfo(w, &info);
    current = info.dwCursorPosition;
 
    if (current.X == last_pos.X && current.Y == last_pos.Y) {
        SetConsoleCursorPosition(w, begin_pos);
    }
    else {
        /* changed by other routines, use the new pos as start */
        begin_pos = current;
    }
    if (is_over)
        SetConsoleTextAttribute(w, FOREGROUND_GREEN);
    //printf("Result: [ %s ]\n", string);
    printf(string);
    if (is_over)
    {
        CString s = CString(string);
        //AfxMessageBox(LPCTSTR(s));
 
        HWND m_hWnd = pFrame->m_hWnd;//->GetMainWnd()->m_hWnd;
 
        SetDlgItemText(m_hWnd, IDC_STATIC, LPCTSTR(s));
        SetDlgItemText(m_hWnd, IDC_STATIC_ACTION, LPCTSTR(s));
 
        CString cmd = CString("C:\\Users\\Danny\\Desktop\\research\\Windows_iat1220_5c82a0db\\samples\\mqtt-publish\\bin\\Debug\\mqtt-publish.exe ");
        if(s.Find(_T("开"))>=0&& s.Find(_T("灯")) >= 0)
            cmd += "开灯";
        else if (s.Find(_T("关")) >= 0 && s.Find(_T("灯")) >= 0)
            cmd += "关灯";
        else
            cmd += "UNKNOWN";
 
        USES_CONVERSION;
        LPCSTR lpcstr = (LPCSTR)T2A(cmd);
 
        WinExec(lpcstr, SW_HIDE);
         
        //PostMessage(pFrame->GetMainWnd()->m_hWnd, WM_MY_MESSAGE, NULL, NULL);
    }
     
    if (is_over)
        SetConsoleTextAttribute(w, info.wAttributes);
 
    GetConsoleScreenBufferInfo(w, &info);
    last_pos = info.dwCursorPosition;
}  

 上面的mqtt-publish.exe就是C#写的下发指令到设备的程序,核心代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
static void Main(string[] args)
        {
            if (args.Length == 0)
                return;
 
            string cmd = args[0];
 
            SendCmdRequest request = new SendCmdRequest();
            request.CmdContent = cmd;
            request.DeviceID = 520355898;
            request.IsByte = true;
            request.Protocol = Scheme.HTTP;
 
            DefaultOneNETClient client = new DefaultOneNETClient("api.heclouds.com", "vYKWEtx7jELTP2V4o=s1NgE1EdA=");
            var response=client.Execute(request);
            Console.WriteLine(response.Body);
 
        }

C#很简单,红色部分是需要根据自己的onenet来改的,需要对应上,用到的nuget库:

ESPDuino部分

花费的时间最多的地方是这个部分,其次是MFC部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <PubSubClient.h>
 
  
const char *ssid = "你的wifi name";
const char *password = "你的wifi密码";
 
 
const char* mqtt_server = "183.230.40.39";
const char* mqtt_device_id="520355898";
const char* mqtt_product_id="223168";
const char* mqtt_api_key="vYKWEtx7jELTP2V4o=s1NgE1EdA=";
 
WiFiClient client;
PubSubClient mqttClient(client);
 
long lastMsg = 0;
char msg_buf[200];
char dataTemplete[]="{\"kq\":%d}";
char msgJson[75];
char debug_buf[200];
int i;
unsigned short json_len=0;
uint8_t* packet_p;
uint8_t debug_buffer_start_index = 0;
 
 
void setup() {
  Serial.begin(115200);
  pinMode(BUILTIN_LED, OUTPUT);
  delay(10);
  
  WifiConnected();
 
  initMQTT();
}
 
void initMQTT()
{
    mqttClient.setServer(mqtt_server, 6002);
    mqttClient.connect(mqtt_device_id,mqtt_product_id,mqtt_api_key);
    mqttClient.setCallback(callback);
}
 
void callback(char* topic, byte* payload, unsigned int length) {
    Serial.print("Message arrived [");
    Serial.print(topic);
    Serial.print("] ");
    for (int i = 0; i < length; i++) {
      Serial.print((char)payload[i]);
    }
    Serial.println();
 
    String s_payload=String((char *)payload).substring(0, length);
    Serial.println(s_payload);
 
    //开灯命令?  
    if (s_payload.equals("关灯")||s_payload.equals("\"关灯\"")) {
      digitalWrite(BUILTIN_LED, LOW);
    } else if (s_payload.equals("开灯")||s_payload.equals("\"开灯\"")){
      digitalWrite(BUILTIN_LED, HIGH);
    }
  
}
 
 
void reconnect() {
  // Loop until we're reconnected
  while (!mqttClient.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (mqttClient.connect(mqtt_device_id,mqtt_product_id,mqtt_api_key)) {  //One net user name as product ID , and password as APIKey
      Serial.println("connected");
      // Once connected, publish an announcement...
      mqttClient.publish("outTopic", "hello world");
      // ... and resubscribe
      mqttClient.subscribe("inTopic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(mqttClient.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}
 
void loop() {
 
    if (!mqttClient.connected()) {
      reconnect();
    }
    mqttClient.loop();
 
    long now = millis();
  if (now - lastMsg > 2000) {
    lastMsg = now;
 
    int kqValue=analogRead(A0);
     
    snprintf(msgJson,sizeof(msgJson),dataTemplete,kqValue);
    json_len=strlen(msgJson); //packet length count the end char '\0'
    msg_buf[0]=char(0x03);  //palyLoad packet byte 1, one_net mqtt Publish packet payload byte 1, type3 , json type2
    msg_buf[1]=char(json_len>>8);  //high 8 bits of json_len (16bits as short int type)
    msg_buf[2]=char(json_len&0xff); //low 8 bits of json_len (16bits as short int type)
   // snprintf(msg_buf+3,40,dataTemplete,value);
    
   memcpy(msg_buf+3,msgJson,strlen(msgJson));
   msg_buf[3+strlen(msgJson)] = 0;
    Serial.print("Publish message: ");
    Serial.println(msgJson);
    mqttClient.publish("$dp",(uint8_t*)msg_buf,3+strlen(msgJson),false);
  }
}
 
 
 
 
void WifiConnected()
{
  WiFi.disconnect();
  WiFi.mode(WIFI_STA);
  
  Serial.println();
  Serial.print("Connecting to");
  Serial.println(ssid);
  
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_DISCONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
 
  randomSeed(micros());
   
  Serial.println("");
  Serial.println("WIFI connected");
  Serial.println(WiFi.localIP());
  
}  

 

至此,可以语音控制和手机控制了。

后续扩展命令会较容易,可以move到C#部分来做,如果觉得语音转文本有不准的地方,目前的想法是通过神经网络来做识别,而不是通过目前的这种很挫的判断办法

 

 OK,完工。

有要代码的就找我发给你。

 

  

 

posted @   McKay  阅读(2223)  评论(2编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示