GitChat 做者:晶晶郭
原文:用語音和天然語言控制智能家居——實例分享
關注公衆號:GitChat 技術雜談,一本正經的講技術html
ZigBee做爲一種短距離、低功耗的無線通訊局域網協議,其優勢是超低功耗、安全性高和自組網,而且可容納多個設備,所以在智能家居控制中佔有很大的優點。前端
同時,隨着人工智能、語音識別、天然語義理解的發展,語音控制智能家居將成爲一種趨勢,這裏會以window java應用程序爲例,講解如何經過語音識別控制智能家居,並輸出ZigBee3.0協議,也很方便和ZigBee協調器進行對接,實現語音直接控制硬件。java
下面詳細介紹程序的功能和代碼實現,但願語音、語義理解從此能普遍的應用在家居等控制領域。git
語音和天然語言控制智能家居輸出Zibee3.0協議實例源碼程序員
注:下載代碼後請仔細閱讀說明文檔。web
APP 測試請查看第3節。windows
APP的工做流程以下圖所示,圖中虛線框部分均由OLAMI開發平臺提供,後面會具體介紹OLAMI開發平臺的使用方法。api
其他部分由APP來完成數組
語音輸入安全
OLAMI的語音識別支持兩種格式:
WAV 格式的 PCM 錄音數據,單聲道(mono)、16K 採樣率(16 KHz Sample Rate)、16 bits 位深(Bit
Resolution)。Speex 音頻壓縮,節省數據傳輸量,壓縮參數:Wideband 模式、Quality(壓縮比)= 十、單聲道(mono)、16K
採樣率(16 KHz Sample Rate)。
首先要確保硬件設備沒有問題,能夠進行正常的語音錄入。在電腦上安裝好麥克風以後,在「開始菜單」中輸入「錄音機」。
而後在彈出的錄音機中點擊「開始錄音」,使用話筒錄音後點擊「中止錄音」後會彈出保存錄音結果的對話框,保存,聽聽聲音正常便可。固然,也可使用QQ等第三方測試麥克風的軟件。
肯定硬件設備無誤以後,只要經過javax.sound.sampled.TargetDataLine調用windows錄音功能,錄下符合OLAMI語音識別接口的聲音數據便可,個人錄音方式是一邊錄音,同時將原始數據經過speex壓縮的方式post給 OLAMI 語音識別的API接口。不是保存爲wav文件以後再上傳,這樣可以提升語音識別的效率。
文字輸入
文字輸入即直接文本輸入,好比「打開空調」,「把彩燈調成紅色」。
處理NLI輸出
即根據OLAMI NLI的語義輸出結果決定如何操做設備,好比當輸入爲「打開燈」時,咱們能夠收到以下JSON數據:
{ "data": { "asr": { "result": "打開燈", "speech_status": 0, "final": true, "status": 0 }, "seg": "打開 燈 ", "nli": [ { "desc_obj": { "status": 0 }, "semantic": [ { "app": "smarthome", "input": "打開燈", "slots": [ { "modifier": [ "open" ], "name": "control_obj", "value": "燈" } ], "modifier": [], "customer": "593664ad84ae0a0a3feec056" } ], "type": "smarthome" } ] }, "status": "ok" }
slots中的「control_obj」即要操做的設備,上面的結果能夠看到須要操做的設備是"燈",動做爲"打開"。應用程序根據這兩個信息就能夠在本身的設備中尋找「燈」這個設備,併發出「打開」命令。
輸出ZigBee 3.0 協議
根據NLI的輸出咱們能夠斷定要控制的設備是燈,而燈的cluster咱們選擇了ZCL_CLUSTER_ID_GEN_ON_OFF
, 根據這個cluster以及等的device ID等輸出命令便可。
鏈接硬件
這裏沒有提供驅動硬件的代碼,但基本流程就是,將ZigBee協調器的開發版經過串口和電腦相連,軟件發出的命令經串口發送給協調器,再由協調器控制ZigBee協議便可。
文字輸入
經過設備選擇能夠切換不一樣的例句。同時,能夠在例句的框裏輸入其餘控制語句,按回車能夠重複輸入。好比:「請幫我打開燈」,「燈給我打開」,「開一下空調」,「空調的溫度提升一點」
語音輸入
點擊」開始錄音」,若是沒有點擊「中止錄音」,3秒以後會自動中止錄音。若是在這以前點擊了「中止錄音」,那麼會及時中止錄音,並進行語音識別。
識別後的文字會顯示在按鈕的上方,以下圖所示:
設備模擬
如上圖所示,應用程序中會模擬彩燈的顏色和空調的溫度、模式、風力,其原理就是根據輸出的Zigbee3.0協議進行顯示。
命令輸出
即輸出ZigBee3.0的協議。下面列出例子中的幾種設備的協議信息。
燈
功能:僅支持打開和關閉
Device Dype: 0x100
命令:
Cluster ID: 0x0300
Cluster ID 的TI定義:ZCL_CLUSTER_ID_GEN_ON_OFF
actionID | Action_frame(1 bit ) | 參數組 | 說明 |
---|---|---|---|
0x00 | 0x01 | 無 | Off,關閉 |
0x01 | 0x01 | 無 | On,打開 |
彩燈
功能:打開,關閉,顏色調節(例子僅支持紅、橙、黃、綠、青、藍、紫),氛圍調節,色調調節。好比運動氛圍、浪漫氛圍、冷色調、暖色調等。
Device Dype:0x0102
命令:
Cluster ID: 0x0006
Cluster ID 的TI定義:ZCL_CLUSTER_ID_GEN_ON_OFF
actionID | Action_frame(1 bit ) | 參數組 | 說明 |
---|---|---|---|
0x00 | 0x01 | 無 | Off,關閉 |
0x01 | 0x01 | 無 | On,打開 |
Cluster ID: 0x0300
Cluster ID 的TI定義:ZCL_CLUSTER_ID_LIGHTING_COLOR_CONTROL
actionID | Action_frame(1 bit ) | 參數組 | 說明 |
---|---|---|---|
0x08 | 0x01 | Attr1,Attr2 | (均爲int16,即兩個字節,數據格式編號爲0x29 ) 設置彩燈的顏色,即R,G,B值。 |
第一個參數的高八位表示R值。
第一個參數的低八位表示G值。
第二個參數的高八位表示B值。
第二個參數的低八位無心義。
電視
功能:打開,關閉,提升下降音量,換臺。
Device Dype:0x0006
命令:
Cluster ID: 0x0006
Cluster ID 的TI定義:ZCL_CLUSTER_ID_GEN_ON_OFF
actionID | Action_frame(1 bit ) | 參數組 | 說明 |
---|---|---|---|
0x00 | 0x01 | 無 | Off,關閉 |
0x01 | 0x01 | 無 | On,打開 |
0x05 | 0x01 | 無 | 提升音量 |
0x06 | 0x01 | 無 | 下降音量 |
Cluster ID: 0x0008
Cluster ID 的TI定義:ZCL_CLUSTER_ID_GEN_LEVEL_CONTROL
actionID | Action_frame(1bit ) | 參數組 | 說明 |
---|---|---|---|
0x00 | 0x01 | 1個字節,uint8 | 切換頻道 |
0x01 | 0x01 | 無 | 切換下個頻道 |
0x02 | 0x01 | 無 | 切換上個頻道 |
空調
功能:
開關功能,即打開和關閉空調。
切換模式,順序爲「自動-製冷-除溼-送風-加熱」模式按順序循環切換,但不支持某個模式的設置。
風力切換,切換順序爲「自動-低速-中低速-中速-中高速-高速-超強」。
其中,製冷和制熱模式支持上述7種風力切換。
送風和自動模式沒有「超強」風力
除溼無風力調節。
注意,僅支持切換,無風力設置。
升高溫度,切換一次,溫度上升一度,基礎範圍是16-30.
下降溫度,每切換一次,溫度降低一度,基礎範圍是16-30
狀態查詢,開關、溫度、風力、模式查詢。
Device Dype:0x0102
命令:
Cluster ID: 0x0300
Cluster ID 的TI定義:ZCL_CLUSTER_ID_LIGHTING_COLOR_CONTROL
actionID | Action_frame(1bit ) | 參數組 | 說明 |
---|---|---|---|
0x00 | 0x01 | 無 | 切換開關 |
0x01 | 0x01 | 無 | 切換模式 |
0x02 | 0x01 | 無 | 切換風速 |
0x03 | 0x01 | 無 | Setup Button |
0x04 | 0x01 | 無 | Setdown Button |
窗簾
功能:
打開,關閉,中止運行,指定窗簾運行的位置。
Device Dype: 0x202
命令:
Cluster ID: 0x102
Cluster ID 的TI定義:ZCL_CLUSTER_ID_CLOSURES_WINDOW_COVERING
actionID | Action_frame(1bit ) | 參數組 | 說明 |
---|---|---|---|
0x00 | 0x01 | 無 | 打開 |
0x01 | 0x01 | 無 | 關閉 |
0x02 | 0x01 | 無 | 窗簾電機中止移動,並返回當前位置的百分比 |
0x04 | 0x01 | 窗簾號房間號,2bytes | 設置窗簾號,房間號.其中高8位是房間號,低8位是窗簾號 |
0x05 | 0x01 | 百分比 | 單位百分比 |
其他設備和傳感器的ZigBee 輸出協議再也不一 一列出,能夠直接在APP中測試。
代碼下載解壓以後,能夠在根目錄找到 smarthome.jar,在windows7 環境下雙擊便可以運行。
應用程序支持的語料除了選項裏的,其餘的類似說法也支持。
由於APP調用了OLAMI的天然語言理解接口,因此首先是必須先寫語法,來匹配智能家居控制語句。好比:「打開燈」,「幫我打開空調」,必須在完成語法以後,才能從OLAMI的接口中獲取NLI結果。語法相關定義和寫法等請參考博客:告訴你如何使用OLAMI天然語言理解開放平臺API製做本身的智能對話助手
若是你但願修改語法,添加更多的句子支持,必須將語法文件導入到歐拉蜜NLI系統。
下載包解壓以後,根目錄找到smarthome.osl,這個就是智能家居支持的語法。而後註冊並登陸歐拉蜜官網,在本身的帳號下找到「應用管理」,並進入NLI系統。以下圖所示。
接着新增模塊,並將智能家居語法smarthome.osl導入,以下圖所示,點擊「新建」並輸入APP的名字「smarthome」,這個名字必須與smarthome.osl的名字相同,不然導入時會報錯。固然也能夠修改,但同時要修改smarthome.ols中APP name相關字段。
模塊建立以後,選擇「上傳OSL文件」,而後選擇smarthome.osl並確認便可。上傳成功以後會進入該模塊內部,而後在例句庫中能夠看到不少智能家居控制的句子,同時也能夠查看Grammar,Rule等。至此OLAMI語法加載完畢。
若是但願獲取句子解析後的結果,必須在歐拉蜜平臺中建立本身的應用程序,名字任意,個人叫「smarthome」。
回到「應用管理」界面-----建立應用程序。
應用程序建立成功以後,還須要把剛纔建立的smarthome 語法模塊添加到應用程序中,一個應用程序能夠支持多個語法模塊。
點擊圖中的「測試」,輸入「打開燈」,就能夠看到JSON格式的語義輸出結果了:
語法模塊配置好以後,點擊應用程序的」查看Key」的按鈕,能夠看到平臺分配的APP Key和APP Secret.
源碼工程是demosourcecode.jar,解壓以後,添加入Eclispe工程,個人開發環境是JDK1.8.
Eclipse Version: Mars.2 Release (4.5.2).
注意:導入工程後,若是出現文字報錯,請將默認編碼修改成UTF-8,方法 Project->Properties->Resource
代碼結構:
替換KEY
在smarthome packge中的NLIProcess.java中,替換以前建立語法應用時的APP Key和APP Secreat:
// * Replace your APP KEY with this variable. private static String appKey = "*****your APP Key******"; // * Replace your APP SECRET with this variable. private static String appSecret = "****your APP Secret*****";
程序入口:
程序入口爲smarthome packge下的window.java,能夠安裝windows Builder插件,直接操做界面。
smarthome packge:
smarthome包裏的源碼包括了APP應用的基本框架,其中:
window.java爲APP入口,即界面。
NLIProces.java表示處理來自OLAMI NLI接口的語義結果.
錄音處理爲:getSemanticBySpeech()
文字處理爲:getSemanticByText(String inputText)
windowVariable.java是window.java和NLIProces.java的數據傳遞媒介, window.java中會將
NLIProcess.java 須要的控件傳過去:
private void initialize() { nliwindowdata.setCmdTable(cmd_table); nliwindowdata.setcolortext(color_text); nliwindowdata.setAnswerText(answer_Text); nliwindowdata.setModetext(mode_text); nliwindowdata.setTempetext(tempe_text); nliwindowdata.setVoicetext(voice_text); nliwindowdata.setWindtext(wind_text); nliwindowdata.setisRed(isred); nliprocess.SetAnswerConfigCom(nliwindowdata);
smartHomeApp.java用來處理智能家居APP的語法解析和命令輸出。是NLIProces.java中其中一個小模塊。 你還能夠在NLI處理中添加其餘處理模塊,好比天氣查詢、詩歌背誦等等。目前NLIprocess.java中僅處理了smarthome相關的NLI輸出:
private void ProcessNLIResults(NLIResult[] nliResults) { // TODO Auto-generated method stub String answer="對不起,你說的話我還不能理解"; boolean isnormal=false; for(int i=0;i<nliResults.length;i++){ NLIResult tempNlI=nliResults[i]; //tempNlI. //voice_text if(tempNlI.getType()!=null&&tempNlI.getType().equals(nliDefinitions.smarthome_app)){
APPSlotEntry.java----處理NLI返回的JSON數據中slots相關信息
OutputMap.java------存放smartHomeApp.java返回給NLIProcess.java的輸出語句和命令。
Smarthome.definition packge
該包是智能家居處理中用到的定義和設備狀態解析。
Demo中模擬了燈,彩燈,電視,空調,傳感器等設備,初始化數據見smartHomeApp.java的InitDeviceData()。
全部設備信息經過ClientHomeAutomation.java解析並存儲。
//key is deviceID Map<String,HomeAutodeviceObjectNew> addedDeviceMapNew=new ConcurrentHashMap<String,HomeAutodeviceObjectNew>();
Smarthome.util
DataBuffer.java 和Microphone.java用來進行麥克風錄音;錄音格式按照歐拉蜜平臺的要求,參數爲16位深採樣率,16KHZ頻率,單聲道。
源碼爲
public Microphone() { this.sampleRate = 16000; this.bigEndian = false; this.signed = true; this.desiredFormat = new AudioFormat (sampleRate, 16, 1, signed, bigEndian); //this.closeBetweenUtterances = closeBetweenUtterances; this.msecPerRead = 100; //this.keepDataReference = keepLastAudio; //this.stereoToMono = stereoToMono; //this.selectedChannel = selectedChannel; //this.selectedMixerIndex = selectedMixerIndex; this.audioBufferSize = 9600; recorderData = new DataBuffer(); }
麥克風的錄音開始和中止經過線程監控完成。直到沒有聲音錄入時,錄音線程纔會觸發錄音中止機制,所以但願中止錄音時必須通Microphone.stopRecording()關閉錄音,程序才能中止錄音。
所以錄音時最好設置默認的錄音時長或者經過標誌來中止錄音,並調用Microphone.stopRecording(),我這裏的默認錄音時長爲3s.
代碼見NLIProcess.java的
//最多錄3秒數據,由於採樣頻率是16000點每秒,每一個點佔兩個字節。 // readcount<=0表示錄音結束 int num=0; int srcint=0; while(readcount > 0 ) { if(total_count >= 48000*2||needstop) break; num++; System.out.println("數據"+(num+1)); total_count += readcount; System.out.println("單數"+readcount); speechrecoginzer.appendAudioFramesData(databytes); readcount = mic.getData(databytes, 0, temsize); } mic.stopRecording();
WaveFileWriter.java能夠爲錄音數據添加wav頭。
和硬件設備對接,須要串口或者USB等將輸出的ZigBee協議發給協調器,由協調器控制各智能設備作出反應。
重磅 Chat 分享:《一場 Chat 讓你搞清 BAT 程序員的技術職級》
分享人:
勝洪宇,一線互聯網公司前端技術組長,掘金簽約做者,前端博客博主,所講課程幫助超過20萬前端小夥伴學習。
Chat簡介:
不少程序員嚮往進入 BAT 這樣的大型互聯網公司,可是又不知道他們如何評定技術職級。
- 阿里集團薪資職級如何劃分?讓你快速獲得馬雲的青睞。
- 在百度明白這些,你將快速晉升。
- 騰訊職級裏的小祕密,這樣工做你會更強。
一場 Chat 讓你搞清 BAT 的技術評價體系,爲您進入超級互聯網公司指明技術方向,時刻作好準備!若是您但願您的技術團隊也像這些互聯網巨頭同樣強大,本場 Chat 我將幫您立刻模仿創建有效的技術職級體系。
想要免費參與本場 Chat ?很簡單,「GitChat技術雜談」公衆號後臺回覆「BAT」