使用Amazon AWS IoT Shadow Service

材料準備

  • Ameba x 1
  • Led x 1

範例說明

  • 簡介 Amazon AWS IoT是一套雲端服務,如同Amazon網站上描述: AWS IoT 是一種讓您能夠將裝置連接至 AWS 服務和其他裝置、保護資料和互動安全、處理和對裝置資料採取動作,以及即使離線也能讓應用程式與裝置互動的平台。(from https://aws.amazon.com/tw/iot/how-it-works/) 底下是AWS IoT的架構圖: 1 (Picture from http://docs.aws.amazon.com/iot/latest/developerguide/aws-iot-how-it-works.html) 圖中左上方的Things可以想成是Ameba,它與MQTT Message Broker建立起TLS加密的Channel之後,經由MQTT Protocol溝通。在Message Broker背後有Thing Shadows,可以讓Ameba離線時,仍能讓控制端留下訊息,在下一次Ameba連線時,Thing Shadow會將訊息傳出。 架構裡的Rules Engine可以針對Thing的行為做限制,也可以接上Amazon的其它服務,這部份不在這次的範例討論裡。
  • 使用AWS IoT主控台 要使用AWS IoT,首先需要開通AWS IoT的服務,你可以在這邊找到登入與註冊的訊息:https://aws.amazon.com/ 開通服務需要填信用卡號來確認使用者,並且現在(2016/06/27)開通服務會在第一年享有優惠,在某個流量以內不收費,或是可以設置流量警示避免繳交不預期的費用。詳細情形請參考網站內容說明。 登入之後,會進入Amazon Management Console,可以看到有很多的Service,點選IoT Core 2 會進入AWS IoT的首頁,如果是第一次使用,會看到底下的簡介畫面。Amazon的service為了效率考量分了好幾個區域,讓使用者可以選較近的server使用,為了確保使用品質,我們先點右上角使用者名稱旁邊的地區選項: 3 接著選擇離自己近的區域 4 選好之後,我們再點選 “Get started” 5 則會帶入AWS IoT 主頁 5 5 左欄有一個“Manage”欄位,而且底下有一個“Things”項目,我們選擇它,右邊則點擊“Register a thing” 6 進入下一頁,點擊“Create a single thing” 6 我們在Name欄位填入 thing的名稱為 “ameba”,屬性可以用來定義 ameba的狀態,ameba可以更新這些狀態,控制端也可以嘗試要求ameba切換到控制端想要的狀態。這裡我們填入屬性名稱為led,值填入0,讓ameba可以更新一個led的狀態。設定完成之後,點選 “Next” 7 進入下一頁我們先點選“Create thing witohut certificate” 8 之後我們能看到一個命名為ambea的Thing被成功創造出來 8 接著我們要開始創建一個Policy,點選左邊欄位Secure底下的“Policies”,並在且右邊頁面點擊“Create a policy” Policy的用途是限制thing的功能,可以限制thing可以執行的MQTT動作,或是限制特定的topic,更多policy的用法可以參考:http://docs.aws.amazon.com/iot/latest/developerguide/authorization.html 8 這裡我們先不作限制,讓整個流程成功之後再調整這部份。我們將policy的名稱填入 “amebaPolicy”,Action填入 “iot:*”,Resources填入 “*”,並在後面的 “Allow”打勾。填完之後點選 “Create”。 9 就完成Policy的設定: 10 接著我們要設定TLS所需的certificate,點選 “Create a certificate”,點擊左欄”Secure-> certificates”,並且在右邊頁面點選”Create a certificate” 11 這裡可以選擇自己定義的certificate,或是網站幫你產生。我們點選 “1-Click certificate create”讓網站幫我們產生。 12 接著會產生四個連結,讓我們可以下載 public key,private key,certificate 與 rootCA。我們將這四個檔案下載。並且點擊”Done”,回到certificates主頁 13 在certificates主頁右上方有一個”Actions”下拉選單,點選”Attach policy” 15 15 選擇剛剛創造的“AmebaPolicy”接著點擊“Attach” 接著再回到certificates主頁右上方”Actions”下拉選單,點選”Attach thing”,出現下圖視窗時選擇剛創建的thing “ameba”,接著點擊“Attach” 16 16 然後我們要啟用certificate,回到certificates主頁並且點選certificate之後,在右邊的Actions下拉選單裡,點選 “Activate”,則此certificate將開始啟用 17 回到左邊欄位,選擇”Manage->Things”,點擊剛新建的ameba thing 18 進入ameba thing的頁面後,在左邊選頁選擇“Interact”,可以看到我們設定Amazon Alexa所需的Rest API Endpoint及一些資訊: — REST API endpoint: 裡面的值是 “https://a1a7oo4baosgyy.iot.us-east-1.amazonaws.com/things/ameba/shadow”,其中 “a1a7oo4baosgyy.iot.us-east-1.amazonaws.com”就是我們可以使用的 MQTT Broker server的位址 — MQTT topic:裡面的值是 “$aws/things/ameba/shadow/update”,代表如果我們想使用AWS IoT Shadow的服務,我們的MQTT topic就得填這個值。但如果我們只想用MQTT的功能,則可以使用其它值。這邊我們建議使用 “$aws/things/ameba/shadow/update”
  • 設定Ameba 我們打開範例 “File” -> “Examples” -> “AmebaMQTTClient” -> “amazon_awsiot_basic” 首先需要先填入Ameba要連上的AP的ssid與password 22 接著填入thing的名稱,這邊我們填入 “ameba”,這個名稱會自動帶入與thing名稱有關的字串裡。 23 接著填入MQTT Broker server的位址,這個位址可以在AWS IoT主控台裡找到,它會在我們新增的thing的資訊欄裡面,這裡我們填入”a1a7oo4baosgyy.iot.us-east-1.amazonaws.com24 接著我們填入TLS會用到的root CA,root CA我們剛剛已在certificate主頁下載,我們可以下載確認一下root CA是否與sketch的root CA相同: 25 接著我們要填入我們在AWS IoT主控台新增的certificate(通常稱之為 client certificate),檔名結尾為 “-certificate.pem.crt” (Ex. “efae24a533-certificate.pem.crt”),我們可以用文字編輯器打開這個檔案,會發現它與sketch的內容不太一樣,我們需要將它調整成字串格式: – 每行後面需要加上換行符號 \n – 每行前後需要加上雙引號 – 為了將字串串接,在行尾加上 \ – 最後一行以分號結束 27 我們在AWS IoT主控台新增certificate時,還有private key的資訊,我們將它填入,一樣要轉成字串格式: 28 到這邊就設定完成了
  • 編譯並執行 我們將sketch編譯並上傳至Ameba之後,按下reset按鈕,打開serial monitor看執行的結果 29 1. 第一步會先連上AP並取得IP Address 2. 接著會嘗試連上MQTT Broker server,這步會花比較久的時間。會看到log裡出現驗證certificate的資訊,最後建立TLS連線成功,顯示 “connected” 3. 連線上之後,Ameba會publish目前的狀態,topic 為 “$aws/things/ameba/shadow/update”,而payload為AWS IoT Shadow的JSON格式。 AWS IoT Shadow的格式可以參考這裡:http://docs.aws.amazon.com/iot/latest/developerguide/thing-shadow-document-syntax.html這裡Ameba只有led的狀態,這個狀態與我們在AWS IoT主控台在新增thing時所添加的狀態是一樣的名稱。這裡我們將 “led” 的狀態填入1,代表將led點亮。 這裡Ameba只有led的狀態,這個狀態與我們在AWS IoT主控台在新增thing時所添加的狀態是一樣的名稱。這裡我們將 “led” 的狀態填入1,代表將led點亮 此時我們可以回到新增的ameba thing的頁面,在欄位左邊點擊“Shadow”,ameba thing右方資訊欄看到資訊已更新,會看到 “Last update”的地方會是最近幾分鐘的時間,並且 “Shadow status” 的內容裡會看到ameba上傳的資訊。 30 如果我們想控制ameba讓led關掉,可以點選右上方的 “Edit” 31 點選之後,會出現 “Shadow state” 的文字方塊,裡面已經有預設的內容 我們將文字方塊的內容改成:
    {
      "desired": {
        "led": 0
      }
    }
    
    代表我們希望將 “led” 的狀態改為 0,改完之後點選 “Save” 33 等一會兒會看到 “led” 的相關狀態都變成 0了,並且 “Last update” 又有一筆新的更新 34 此時回到 Serial Monitor會看到新的訊息 1. 進來了一筆標題為 “$aws/things/ameba/shadow/update/accepted” 的訊息,內容有剛剛我們在AWS IoT主控台填寫的內容 2. Ameba收到前一筆訊息時,解析它的內容,發現 “led” 狀態變成0,於是將led關掉,並且publish新的狀態上去 3. 同時進來另外一筆標題為 “$aws/things/ameba/shadow/update/delta”的內容 4. 最後MQTT Broker又送一筆標題 “$aws/things/ameba/shadow/update/accepted”的訊息,回應ameba最新一筆的publish 35 這個過程到這邊結束,我們總共使用了 AWS IoT主控台,設定了TLS加密所需的certificate,也設定了MQTT Brokder,最後使用AWS IoT Shadow操作與更新ameba的狀態。Amazon提供了詳細的文件,可以在這裡找到更多相關資訊:http://docs.aws.amazon.com/iot/latest/developerguide/

程式碼說明

整份程式碼使用了基本的MQTT架構,除了AWS IoT的MQTT Broker Server與TLS certificate設定可以參考前面的說明之外,程式碼說明如下
  • 設定led狀態 這部份是一般的GPIO應用,預設led_pin為10,led_state為1
     
    pinMode(led_pin, OUTPUT);
    digitalWrite(led_pin, led_state);
    
  • 連線至AP 這部份是一般的wifi連線程式碼,沒有不同的地方
  • 設定certificate 這部份就有點不同,其中我們的wifiClient的型態是
    WiFiSSLClient wifiClient;
    
    WiFiSSLClient繼承了Client,所以也可以當作PubSublicant的constructor參數 在連線之前,我們設定TLS相關的certificate
    wifiClient.setRootCA((unsigned char*)rootCABuff);
    wifiClient.setClientCertificate((unsigned char*)certificateBuff, (unsigned char*)privateKeyBuff);
    
  • 設定MQTT Broker server 接著MQTT PubClient設定MQTT Broker server並且連線
    client.setServer(mqttServer, 8883);
    client.setCallback(callback);
    
    注意到這邊的port是8883,一般來說,如果MQTT底層走的是TLS協定,使用的port會是8883
  • 連線至MQTT Broker server 進入loop()之後,會呼叫reconnect()並且嘗試連線,這邊也是log裡出現驗證certificate的地方:
    while (!client.connected()) {
    
  • Subscribe & Publish 連線成功之後,註冊要傾聽的topic
    for (int i=0; i<5; i++) {
      client.subscribe(subscribeTopic[i]);
    }
    
    常用的topic有這些 “$aws/things/ameba/shadow/update/accepted”, “$aws/things/ameba/shadow/update/rejected”, “$aws/things/ameba/shadow/update/delta”, “$aws/things/ameba/shadow/get/accepted”, “$aws/things/ameba/shadow/get/rejected” 簡易的說明可以參考這裡: http://docs.aws.amazon.com/iot/latest/developerguide/thing-shadow-data-flow.html 註冊完之後,我們publish目前的狀態
    sprintf(publishPayload, "{\"state\":{\"reported\":{\"led\":%d}},\"clientToken\":\"%s\"}", led_state, clientId);
    client.publish(publishTopic, publishPayload);
    
  • 傾聽topic並做出回應 我們在callback裡傾聽先前註冊的5個topic,並且檢查是否有 “/shadow/get/accepted
    if (strstr(topic, "/shadow/get/accepted") != NULL) {
    
    如果有的話,代表控制端送了訊息過來,我們解析裡面的內容,如果led狀態與現在不同,則publish新的狀態
    updateLedState(desired_led_state);
    
請先確認已安裝QQ通訊軟體