Ameba Arduino: [RTL8195] Amazon Service

Alexa 簡介

Alexa 是 Amazon 底下的智慧語音服務,它能聆聽使用者的語句,並且以語音回答。
底下是Amazon的Alexa影片介紹: https://www.youtube.com/watch?v=UOEIH2l9z7c

Amazon也推出實體產品像是Amazon Echo智慧音箱,裡面搭載Alexa服務: https://www.youtube.com/watch?v=FQn6aFQwBQU

語音服務的使用情境裡,使用者不用再 “拿起” 或 “掀開” 3C產品,第一步通常是用關鍵字喚醒產品,像是說出 “Alexa”, 接著可以說出一些問題或命令。像是今天天氣如何,播放音樂,設定一小時後的鬧鐘。
Alexa同時也支援Alexa Skill,讓3rd party的個人或公司參與開發。像是可以下載說故事的Alexa Skill,Alexa就擁有說故事的能力。
Alexa Skill裡面也包含智慧家庭的服務,支援常見的智慧家庭的產品像是智慧燈泡、智慧開關、智慧門鎖等等……。
這個範例裡,會介紹如何讓Ameba也支援Alexa的服務,讓使用者可以對Ameba詢問今天有什麼新聞,或是控制支援AWS IoT的產品,像是之前的範例裡示範過如何用Alexa經由AWS IoT開關Ameba上的燈泡。

準備事項

Alexa服務包含了 AVS (Alexa Voice Service) 以及 ASK(Alexa Skill Kit),要讓Ameba支援Alexa最主要需要設定與支援AVS。另外Ameba的語音處理需要一塊支援I2S的Audio codec、一個喇叭。

1. Ameba * 1
2. ALC5680 *1
3. Button *1
4. Speaker *1

  • 設定 Alexa Voice Service

第一次使用可以參考官方文件做設定
https://developer.amazon.com/public/solutions/alexa/alexa-voice-service/getting-started-with-the-alexa-voice-service#register

它分成4個步驟:

  • Step 1: Register Your Product
    這部份主要是帳號設定
  • Step 2: Prototype
    這部份我們會在Ameba上面寫程式支援Alexa,到這一步已經可以做一些基本的控制
  • Step 3: Design and Build with AVS
    這部份則是細節控制,像是設定麥克風數量、裝置預設的距離等等。這個範例裡我們不會執行到這步
  • Step 4: Launch Your Product
    這部份是關於如何將產品上市。這個範例裡我們不會執行到這步
  • 註冊成為Amazon開發者

第一步裡,要先成為Amazon 開發者,第一次設定會先填寫註冊表單

https://developer.amazon.com/registration/profile.html

2
填完之後,點選表單後面的 “Save and Continue”
接著會出現同意書,閱讀完之後如果同意請點選 “Accept and Continue”
接著會詢問App內購與廣告的資訊,這部份可以之後再更改,我們先跳過,點選 “Save and Continue”

  • 新增AVS App

填完之後會來到Amazon開發者的管理後台
我們點選 “APPS & SERVICES” => “Alexa”,會出現 “Alexa Skill Kit” 與 “Alexa Voice Service”,我們點選 “Alexa Voice Service”

2

  • Product Information

這個頁面裡要填寫deivce相關的資訊:
1. Product Name: 這裡的資訊應該會與我們在註冊成為開發者的一樣
2. Product Type ID: 只能使用字母, 數字, 與底線。這裡面的內容會在範例裡用到
3. Product Type: 選擇Alexa-Enabled Device

其他欄位及選項如下列圖片所示,結束後按NEXT

2

2

2

  • Security Profile

接著要設定Security profile,如果之前沒有設定過,就需要新增一個,我們點選 “Create a new profile”

2
在 General裡有兩個欄位要填:
1. Security Profile: Security profile的名字
2. Security Profile Description: Security profile的描述
填完之後按 “Next” 即會產生Security Profile ID

2

接著會產生一組 Client ID 與 Client Secret,這裡面的內容會在範例裡用到,我們可以先記下來,或是之後再回來查看。

2

接著要填寫的是當使用者要授權Ameba使用Alexa的時候,要到哪個網址取得訊息,以及該如何將授權訊息回傳。這裡我們使用mDNS的位址:
1. Allowed Origins: https://localhost:3000
2. Allowed Return URLs: https://localhost:3000/authresponse
填完之後點分別在欄位右邊按下”ADD”,接著按下”UPDATE”

2

之後出現上圖的頁面代表設定大功告成。

  • Enable security profile

接著我們要啟用前面設定好的 Security profile https://developer.amazon.com/lwa/sp/overview.html
選擇剛剛設定的 Security Profile,並點選 “Confirm”

2
接著要填寫第一次登入使用時,要顯示privacy policy的URL,可以任填。這裡我們填一樣的mDNS位置。然後點選 “Save”

2

到這裡就完成AVS的設定

  • 申請Refresh Token

為了減少本範例在運作期間,進行申請Refresh Token所花費的耗能,我們提前在範例運作前先作申請。

在Ameba8195的Github上提供了Windows/Linux的申請工具:
https://github.com/Ameba8195/Arduino/tree/master/misc/amazon_alexa_avs_auth_tool

在執行前得先使用openssl產生certificate

openssl genrsa -out ca.key 4096
openssl req -new -x509 -days 365 -key ca.key -out ca.crt -sha256

會產生ca.key及ca.crt兩個檔案,將這兩個檔案與申請工具放在同一個資料夾而在Linux下則需要先將Refresh Token tool申請工具編譯:

gcc -o amz_oauth_linux amz_oauth_linux.c -lssl -lcrypto

並且執行

./amz_oauth_linux

如果在Windows底下可以開啟cmd執行Refresh Token申請工具:amz_oauth_windows.exe

2

上圖是Refresh Token tool執行期的畫面,以下需要填入剛在Alexa Voice Service申請取得的相關欄位資訊

1. device id: 這裡請填Product ID
2. device dsn: 通常是一組流水號,目前還未有具體的使用情境,我們先任意填
3. client id: 這裡請填Client ID
4. client secret: 這裡請填client secret
5. allowed origins: 這裡請填https://localhost:3000
6. allowed return urls: 這裡請填https://localhost:3000/authresponse
7. server port: 這裡請填3000

之後會跑出如上圖標示紅框處的一段連結,將這段連結拷貝組合後貼上瀏覽器進行Refresh Token的申請,如果申請成功,頁面會顯示Refresh Token的參數,並且原來的cmd console也會顯示Refresh Token(如上圖標示藍框處)

2

材料準備

  • Audio codec

Ameba本身有I2S的介面可以處理Audio data,這個範例裡我們使用Realtek Audio Shield做為I2S的資料來源。

Realtek Audio Shield使用的IC是ALC5680,通常Audio codec至少會使用到一組I2S與I2C。I2S是資料I/O,I2C則是初始與選項設定。底下是Realtek Audio Shield的官網介紹
http://www.realtek.com.tw/press/newsViewOne.aspx?NewsID=441

  • 喇叭

這塊Audio codec上面並沒有喇叭,所以我們還需要外接喇叭。

喇叭的部份,用一般支援LINE IN的喇叭即可。

接線與範例設定

  • 接線

Realtek Audio Shield可以完整與Ameba嵌合,在Realtek Audio Shield上另外還需要一個按鈕用來喚醒Ameba的Alexa服務(下圖標示紅框處)
2

接著我們將Ameba接上Audio Shield 與喇叭。

2

  • 上傳程式

接著我們打開範例 “File” -> “Examples” -> “AmebaAudio” -> “alexa_basic”
Alexa服務需要使用到網路,這裡我們修改SSID & PASS成欲連上的WiFi AP SSDI & PASS

2
接著要填寫與AVS服務相關的資訊,說明如下:

2

  • avs_refresh_token: 此欄位填入由refresh token申請工具取得的refresh token。
  • avs_client_id: 這裡的 client id就是之前設定 AVS時取得的client id
  • avs_client_secret: 這裡的 client secret 就是之前設定 AVS 時取得的 client secret
  • avs_http2_host: 提供辨識語音的host,目前Amazon提供好幾組host供不同語系的使用者使用。這裡我們填美國在使用的host

填完之後就可以編譯上傳至Ameba

  • 測試

在Realtek Audio Shield上的按鈕用於喚醒Ameba,我們將它按著,講話,然後放開,Ameba就會將語音資料上傳到雲端,雲端會回傳語音回應至Ameba,Ameba再將它播放。

請參考底下影片的示範:

程式碼說明

  • 程式碼
  • setup_alexa()

在 setup_alexa() 這個函式裡,設定了所有Alexa需要的資訊

Alexa.setAvsClientId(avs_client_id,sizeof(avs_client_id)-1);

設定Client ID,Client ID的值是使用者申請Alexa APP時取得

Alexa.setAvsClientSecret(avs_client_secret, sizeof(avs_client_secret)-1);

設定 Client Secret,Client Secret的值是使用者申請Alexa APP時取得

Alexa. setAvsRefreshToken (avs_refresh_token, sizeof(avs_refresh_token)-1 );

設定儲存Refresh token。當初次設定完成之後,會呼叫這個函式將Refresh token存在 Flash memory裡

Alexa.setAvsHttp2Host(avs_http2_host, sizeof(avs_http2_host)-1);

設定提供AVS語音服務的網站。Amazon目前提供的是基於HTTP2的語音服務。不同語系使用的網站不同

Alexa.begin();

最後啟始AVS語音服務功能

  • loop()

在loop()函式裡,只要持續檢查網路狀態即可,如有異常則進行網路重連

void loop() {
  if (WiFi.status() != WL_CONNECTED) {
      while (WiFi.begin(ssid, pass) != WL_CONNECTED) 
      {
        delay(1000);
      }
      Serial.println("Connected to wifi");
  }
	delay(100);
}
  • Log說明

這小節針對Serial Monitor的log做個說明,底下是已經註冊過Alexa的Ameba的完整log,我們一一說明

Interface 0 IP address : 192.168.88.32Connected to wifi

[HTTPD] httpd_server_thread started
init mdns
SGTL5000 CHIP ID:0xA011

[HTTPC] Use ciphersuite TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256

version=[HTTP/1.1]

status=[200 OK]

content_type=[application/json]

content_lenght=1233
[14316] update access_token:Atza|IwEBIJYyUjyCv8luvwAI7TQyL-j
[14333] update refresh_token:Atzr|IwEBIIW2_8KvJd9qake23w12WQT
[15664] connecting...
[24210] handshake done
[24239] C->S HEADERS
        :method: GET
        :path: /v20160207/directives
        :scheme: https
        :authority: avs-alexa-na.amazon.com:443
        accept: */*
        authorization: Bearer Atza|IwEBIJYyUjyCv8luvwAI
[24308] C->S HEADERS
        :method: POST
        :path: /v20160207/events
        :scheme: https
        :authority: avs-alexa-na.amazon.com:443
        accept: */*
        authorization: Bearer Atza|IwEBIJYyUjyCv8luvwAI
        content-type: multipart/form-data; boundary=bo
[24546] CS HEADERS
        :method: POST
        :path: /v20160207/events
        :scheme: https
        :authority: avs-alexa-na.amazon.com:443
        accept: */*
        authorization: Bearer Atza|IwEBIJYyUjyCv8luvwAI
        content-type: multipart/form-data; boundary=bo
[33363] upload audio................................
[36861] C<-S HEADERS
        :status: 200
        access-control-allow-origin: *
        x-amzn-requestid: 0ed21ffffef23a7d-000069fb-00025786-cd4862c89753e4bd-3736a86a-5
        content-type: multipart/related;boundary=36697d04-4d4e-4595-b6e6-a390edd0295a;start=metadata.1494256392289;type="application/json"
[37551] json: {"directive":{"header":{"namespace":"Speaker","name":"SetMute","messageId":"664d09e5-d664-4948-bbac-c70e08a1424d","dialogRequestId":"64567a10-0a67-48e6-8d66-4a936508f032"},"payload":{"mute":false}}}
[37606] json: {"directive":{"header":{"namespace":"SpeechSynthesizer","name":"Speak","messageId":"fe57a3bb-2280-4d88-9345-529e51cc30f2","dialogRequestId":"64567a10-0a67-48e6-8d66-4a936508f032"},"payload":{"url":"cid:DeviceTTSRenderer_0ae4a760-fee0-407a-b8d1-e5922c967805_1092807486","format":"AUDIO_MPEG","token":"amzn1.as-ct.v1.Domain:Application:Notifications#ACRI#DeviceTTSRenderer_0ae4a760-fee0-407a-b8d1-e5922c967805"}}}
[37718] download mp3.......
(3096)
  • 連上Alexa

接著要嘗試連上Alexa基於HTTP2提供的語音服務。從connecting到收送第一筆http資料不可以超過10秒,超過的話會被Amazon踢掉,並且要嘗試重連。
以底下為例,我們在15.664秒時嘗試連線,在24.210秒完成SSL交握,並在24.239秒送出HTTP封包,在24.546秒時收到Amazon回傳的HTTP封包

[15664] connecting...
[24210] handshake done
[24239] C->S HEADERS
        :method: GET
        :path: /v20160207/directives
        :scheme: https
        :authority: avs-alexa-na.amazon.com:443
        accept: */*
        authorization: Bearer Atza|IwEBIJYyUjyCv8luvwAI
[24308] C->S HEADERS
        :method: POST
        :path: /v20160207/events
        :scheme: https
        :authority: avs-alexa-na.amazon.com:443
        accept: */*
        authorization: Bearer Atza|IwEBIJYyUjyCv8luvwAI
        content-type: multipart/form-data; boundary=bo
[24546] C<-S HEADERS
        :status: 200
        access-control-allow-origin: *
        x-amzn-requestid: 0ed21ffffef23a7d-000069fb-00025786-cd4862c89753e4bd-3736a86a-1
        content-type: multipart/related; boundary=------abcde123; type=application/json
[25716] C<-S HEADERS
        :status: 204
        access-control-allow-origin: *
        x-amzn-requestid: 0ed21ffffef23a7d-000069fb-00025786-cd4862c89753e4bd-3736a86a-3
  • 上傳與下載語音

底下的log會出現在使用者按下按鈕開使錄音,同時Ameba會將資料上傳至Amazon。每上傳一小塊資料便會印一個逗號 “.”

[33295] C->S HEADERS
        :method: POST
        :path: /v20160207/events
        :scheme: https
        :authority: avs-alexa-na.amazon.com:443
        accept: */*
        authorization: Bearer Atza|IwEBIJYyUjyCv8luvwAI
        content-type: multipart/form-data; boundary=bo
[33363] upload audio................................

上傳完之後,可能會等一會兒,才會收到語音回應的內容
語音內容是邊下載邊播放,每下載一小塊資料也會印一個逗號 “.”。

我們不需要等到語音完全下載完才播放。以這份log為例, “(3096)” 代表從使用者放開按鈕直到聽到語音回音的時間是3.096秒,這個時間越短代表使用者感受到的延遲越短。

[36861] C<-S HEADERS
        :status: 200
        access-control-allow-origin: *
        x-amzn-requestid: 0ed21ffffef23a7d-000069fb-00025786-cd4862c89753e4bd-3736a86a-5
        content-type: multipart/related;boundary=36697d04-4d4e-4595-b6e6-a390edd0295a;start=metadata.1494256392289;type="application/json"
[37551] json: {"directive":{"header":{"namespace":"Speaker","name":"SetMute","messageId":"664d09e5-d664-4948-bbac-c70e08a1424d","dialogRequestId":"64567a10-0a67-48e6-8d66-4a936508f032"},"payload":{"mute":false}}}
[37606] json: {"directive":{"header":{"namespace":"SpeechSynthesizer","name":"Speak","messageId":"fe57a3bb-2280-4d88-9345-529e51cc30f2","dialogRequestId":"64567a10-0a67-48e6-8d66-4a936508f032"},"payload":{"url":"cid:DeviceTTSRenderer_0ae4a760-fee0-407a-b8d1-e5922c967805_1092807486","format":"AUDIO_MPEG","token":"amzn1.as-ct.v1.Domain:Application:Notifications#ACRI#DeviceTTSRenderer_0ae4a760-fee0-407a-b8d1-e5922c967805"}}}
[37718] download mp3.......
(3096)