HoloLens (第 1 代) 和 Azure 313:IoT 中樞 服務

注意

混合實境學院教學課程的設計是以 HoloLens (第 1 代) 和混合實境沉浸式頭戴裝置為準。 因此,對於仍在尋找這些裝置開發指引的開發人員而言,我們覺得這些教學課程很重要。 這些教學課程不會使用用於 HoloLens 2 的最新工具組或互動進行更新。 系統會保留這些資訊,以繼續在支援的裝置上運作。 未來將會張貼一系列新的教學課程,示範如何針對 HoloLens 2 進行開發。 此通知會在張貼時更新這些教學課程的連結。

課程成果

在此課程中,您將瞭解如何在執行Ubuntu16.4作業系統的虛擬機上實作 Azure IoT 中樞服務。 然後, Azure 函式應用程式 將用來接收來自 Ubuntu VM 的訊息,並將結果儲存在 Azure 資料表服務內。 然後,您將能夠在 Microsoft HoloLens 或沉浸式 (VR) 頭戴式裝置上使用 Power BI 來檢視此數據。

本課程的內容適用於 IoT Edge 裝置,但基於本課程的目的,焦點會放在虛擬機環境上,因此不需要存取實體Edge裝置。

完成本課程后,您將瞭解如何:

  • IoT Edge 模組部署到虛擬機 (Ubuntu 16 OS) ,這代表 IoT 裝置。
  • 使用程式代碼將 Azure 自訂視覺 Tensorflow 模型新增至 Edge 模組,以分析儲存在容器中的影像。
  • 設定模組,將分析結果訊息傳回您的 IoT 中樞 服務
  • 使用 Azure 函式應用程式 將訊息儲存在 Azure 資料表內。
  • 設定 Power BI 以收集儲存的訊息並建立報表。
  • Power BI 中將 IoT 訊息資料可視化。

您將使用的服務包括:

  • Azure IoT 中樞 是 Microsoft Azure 服務,可讓開發人員連線、監視和管理 IoT 資產。 如需詳細資訊,請流覽 Azure IoT 中樞 服務頁面

  • Azure Container Registry 是 Microsoft Azure 服務,可讓開發人員儲存各種容器類型的容器映像。 如需詳細資訊,請流覽 Azure Container Registry 服務頁面

  • Azure 函式應用程式 是 Microsoft Azure 服務,可讓開發人員在 Azure 中執行小型程式代碼片段『functions』。 這提供將工作委派給雲端的方式,而不是您的本機應用程式,這有許多優點。 Azure Functions 支援數種開發語言,包括 C#、F#、Node.js、Java 和 PHP。 如需詳細資訊,請流覽 Azure Functions 頁面

  • Azure 記憶體:數據表 是 Microsoft Azure 服務,可讓開發人員在雲端中儲存結構化、非 SQL、數據,使其可在任何地方輕鬆存取。 服務會降低架構設計,視需要允許數據表的演進,因此非常有彈性。 如需詳細資訊,請流覽 Azure 數據表 頁面

本課程將教導您如何設定及使用 IoT 中樞 服務,然後將裝置所提供的響應可視化。 您必須將這些概念套用至您可能要建置的自訂 IoT 中樞 服務設定。

裝置支援

課程 HoloLens 沉浸式頭戴裝置
MR 和 Azure 313:IoT 中樞服務 ✔️ ✔️

Prerequisites

如需使用 Mixed Reality 進行開發的最新必要條件,包括使用 Microsoft HoloLens,請瀏覽安裝工具一文。

注意

本教學課程專為具備 Python 基本經驗的開發人員所設計。 另請注意,本檔中的必要條件和書面指示代表在撰寫 (2018 年 7 月) 時已經過測試和驗證的內容。 您可以自由使用最新的軟體,如 安裝工具 一文中所列,但不應該假設本課程中的資訊完全符合您在較新軟體中所找到的內容,而不是下面所列。

需要下列硬體和軟體:

  • Windows 10 Fall Creators Update (或更新版本) ,已啟用開發人員模式

    警告

    您無法在 Windows 10 家用版 Edition 上使用 Hyper-V 執行虛擬機。

  • Windows 10 SDK (最新版本)

  • 已啟用 HoloLens、 開發人員模式

  • Visual Studio 2017.15.4 (僅用來存取 Azure Cloud Explorer)

  • 適用於 Azure 和 IoT 中樞 服務的因特網存取。 如需詳細資訊,請遵循此連結來 IoT 中樞 服務頁面

  • Machine Learning 模型。 如果您還沒有自己的模型可供使用, 您可以使用本課程所提供的模型

  • 在您的 Windows 10 開發計算機上啟用 Hyper-V 軟體。

  • 執行Ubuntu的虛擬機 (16.4或18.4) 、在您的開發電腦上執行,或者您可以使用執行Linux的個別電腦, (Ubuntu16.4或18.4) 。 如需有關如何 使用 Hyper-V 在 Windows 上使用 Hyper-V 建立 VM 的詳細資訊,請參閱 一章

開始之前

  1. 設定及測試 HoloLens。 如果您需要設定 HoloLens 的支援, 請務必流覽 HoloLens 設定一文
  2. 在開始開發新的 HoloLens 應用程式時,最好先執行 校正感測器微調 (有時有助於為每個使用者執行這些工作) 。

如需校正的說明,請遵循此 連結至 HoloLens 校正文章

如需感測器微調的說明,請遵循此 連結至 HoloLens 感測器微調文章

  1. 使用 Hyper-V 設定您的 Ubuntu 虛擬機。 下列資源將協助您進行此程式。

    1. 首先,請遵循此鏈接下載 Ubuntu16.04.4 LTS (Xenial Xerus) ISO。 選取 64 位電腦 (AMD64) 桌面映射
    2. 請確定 Windows 10 計算機上已啟用 Hyper-V。 您可以遵循此連結,以取得在 Windows 10 上安裝和啟用 Hyper-V 的指引。
    3. 啟動 Hyper-V 並建立新的 Ubuntu VM。 如需 如何使用 Hyper-V 建立 VM 的逐步指南,您可以遵循此連結。 當要求 「從可開機映像檔案安裝操作系統」時,請選取您稍早下載的 Ubuntu ISO

    注意

    不建議使用 Hyper-V 快速建立

第 1 章 - 擷取 自訂視覺 模型

透過本課程,您將能夠存取預先建置的 自訂視覺 模型,以偵測影像中的鍵盤和滑鼠。 如果您使用此選項,請繼續進行 第 2 章

不過,如果您想要使用自己的 自訂視覺 模型,您可以遵循下列步驟:

  1. 自訂視覺 專案中,移至 [效能] 索引標籤。

    警告

    您的模型必須使用 精簡 定義域來導出模型。 您可以在項目的設定中變更模型定義域。

    效能索引標籤

  2. 選取您要導出的 反覆 專案,然後按兩下 [ 匯出]。 刀鋒視窗隨即出現。

    匯出刀鋒視窗

  3. 在刀鋒視窗中,按兩下 [Docker 檔案]。

    選取 docker

  4. 單擊下拉功能表中的 [Linux ],然後按兩下 [ 下載]。

    按兩下 [下載]

  5. 解壓縮內容。 您將在本課程稍後使用它。

第 2 章 - Container Registry Service

Container Registry Service 是用來裝載容器的存放庫。

您將在此課程中建置及使用的 IoT 中樞 服務是指 Container Registry Service,以取得要部署在 Edge 裝置中的容器。

  1. 首先,遵循此 連結至 Azure 入口網站,並使用您的認證登入。

  2. 移至 [建立資源 ],並尋找 Container Registry

    容器登錄

  3. 按一下 [建立]。

    顯示選取 [建立位置] 的螢幕快照。

  4. 設定服務設定參數:

    1. 插入項目的名稱,在此範例中,其稱為 IoTCRegistry

    2. 選擇 資源群組 或建立新的群組。 資源群組可讓您監視、控制存取、布建和管理 Azure 資產集合的計費方式。 建議將所有與單一專案相關聯的 Azure 服務保留 (例如,這些課程) 在通用資源群組) 下。

    3. 設定服務的位置。

    4. 管理員 用戶設定為 [啟用]。

    5. SKU 設定為 [基本]。

    顯示 SKU 設定為 [基本] 位置的螢幕快照。

  5. 按兩下 [建立 ],並等候服務建立。

  6. 當通知快顯通知您 容器登錄成功建立之後,請按兩下 [ 移至資源 ] 以重新導向至您的 [服務] 頁面。

    顯示選取 [移至資源位置] 的螢幕快照。

  7. [Container Registry Service] 頁面中,按兩下 [ 存取密鑰]。

  8. 記下 (您可以使用記事本) 下列參數:

    1. 登入伺服器
    2. 使用者名稱
    3. 密碼

    顯示檢視 [登入伺服器]、[使用者名稱] 和 [密碼] 參數位置的螢幕快照。

第 3 章 - IoT 中樞 服務

現在,您將開始建立和設定 IoT 中樞 服務

  1. 如果尚未登入,請登入 Azure 入口網站

  2. 登入之後,按兩下左上角的 [建立資源],然後搜尋 IoT 中樞,然後按兩下 Enter

顯示 [所有專案] 視窗開啟的螢幕快照。搜尋結果中的 I O T 中樞和左上角的 [建立資源] 會以紅色圓圈。

  1. 新頁面將提供 記憶體帳戶 服務的描述。 在此提示的左下角,按兩下 [ 建立 ] 按鈕,以建立此服務的實例。

    顯示 [I O T 中樞概觀] 頁面的螢幕快照。

  2. 按兩下 [ 建立] 之後,會出現面板:

    1. 選擇 資源群組 或建立新的群組。 資源群組提供一種方式來監視、控制存取、布建和管理 Azure 資產集合的計費。 建議將所有與單一專案相關聯的 Azure 服務保留 (例如,這些課程) 在通用資源群組) 下。

      如果您想要深入瞭解 Azure 資源群組,請遵循此 連結以瞭解如何管理資源群組

    2. 選取適當的 位置 (在此課程中建立的所有服務) 使用相同的位置。

    3. 插入此服務實例所需的 Name

  3. 按兩下頁面底部的[ 下一步:大小和小數字數]。

    顯示 [I O T 中樞基本概念] 頁面的螢幕快照。下一個大小和小數字數會以紅色圓圈在頁面底部。

  4. 在此頁面中,如果這是您的第一個 IoT 中樞 服務實例,請選取您的定價和調整層 (,) 應該可以使用免費層。

  5. 按兩下 [ 檢閱 + 建立]。

    顯示 [I O T 中樞大小和縮放比例] 頁面的螢幕快照。F 1 免費層已選取 [定價和調整層] 欄位中。檢閱和建立會在頁面底部以紅色圓圈。

  6. 檢閱您的設定,然後按兩下 [ 建立]。

    顯示 [I O T 中樞檢閱和建立] 頁面的螢幕快照。建立會在頁面底部以紅色圓圈。

  7. 當通知快顯通知您成功建立 IoT 中樞 服務之後,請按兩下 [移至資源] 以重新導向至您的 [服務] 頁面。

    顯示部署成功通知的螢幕快照。[移至資源] 按鈕會以紅色圓圈。

  8. 捲動左側面板,直到您看到 [自動 裝置管理],然後按兩下 [IoT Edge]。

    顯示 [自動 裝置管理] 下方功能表中已選取 [I O T Edge] 的螢幕快照。

  9. 在右側顯示的視窗中,按兩下 [新增 IoT Edge 裝置]。 刀鋒視窗會出現在右側。

  10. 在刀鋒視窗中,提供新裝置的 [ 裝置標識符 ] (您選擇的) 名稱。 然後按一下 [ 儲存]。 如果您已自動產生自動產生則主要次要金鑰會自動產生。

    顯示 [新增裝置] 頁面的螢幕快照。Edge Device 0 1 會在 [裝置標識符] 字段中輸入。已核取 [自動產生金鑰] 方塊。

  11. 您將流覽回 [IoT Edge 裝置] 區段,其中會列出新裝置。 按兩下圖) 中紅色概述的新裝置 (。

    顯示 [I O T Edge 裝置] 頁面的螢幕快照。此方塊會在頁面底部的Edge裝置旁邊核取。

  12. 在顯示的 [ 裝置詳細數據] 頁面上,取得 連接字串 複本, (主鍵) 。

    顯示 [裝置詳細數據] 頁面的螢幕快照。連接字串主鍵會以紅色圓圈。

  13. 返回 至左側面板,然後按兩下 [共用存取原則] 加以開啟。

  14. 在出現的頁面上,按兩下 [iothubowner],畫面右側會出現刀鋒視窗。

  15. 記下 [記事本] 上的 ([記事本]) ( 主鍵) ,以供稍後在將連接字元串設定為裝置時使用。

    顯示 [共用存取原則] 頁面的螢幕快照,其位於 [設定] 底下。[原則] 底下已選取 [I O T 中樞擁有者]。在彈出視窗中,連接字串 主鍵欄位會以紅色圓圈。

第 4 章 - 設定開發環境

若要建立和部署 IoT 中樞 Edge 的模組,您必須在執行 Windows 10 的開發電腦上安裝下列元件:

  1. Docker for Windows 會要求您建立能夠下載的帳戶。

    下載適用於 Windows 的 Docker

    重要

    Docker 需要 Windows 10 PROEnterprise 14393Windows Server 2016 RTM 來執行。 如果您正在執行其他版本的 Windows 10,您可以嘗試使用 Docker 工具箱安裝 Docker

  2. Python 3.6

    下載 python 3.6

  3. Visual Studio Code (也稱為 VS Code)

    下載 VS Code

安裝上述軟體之後,您必須重新啟動電腦。

第 5 章 - 設定 Ubuntu 環境

現在您可以繼續設定執行 UbuntuOS的裝置。 請遵循下列步驟來安裝必要的軟體,以在您的面板上部署您的容器:

重要

您應該一律在終端機命令前面加上 sudo ,以系統管理員使用者身分執行。 亦即:

sudo docker \<option> \<command> \<argument>
  1. 開啟 Ubuntu 終端機,並使用下列命令來安裝 pip

    [!HINT] 您可以使用鍵盤快捷方式輕鬆地開啟 終端機Ctrl + Alt + T

        sudo apt-get install python-pip
    
  2. 在本章中,您可能會收到 [終端機] 的提示,以取得使用裝置儲存空間的許可權,以及輸入 y/n (yes 或 no) ,輸入 'y',然後按 Enter 鍵以接受。

  3. 完成該命令之後,請使用下列命令來安裝 curl

        sudo apt install curl
    
  4. 安裝 pipcurl 之後,請使用下列命令來安裝 IoT Edge 運行時間,這是在面板上部署和控制模組的必要專案:

        curl https://packages.microsoft.com/config/ubuntu/16.04/prod.list > ./microsoft-prod.list
    
        sudo cp ./microsoft-prod.list /etc/apt/sources.list.d/
    
        curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg
    
        sudo cp ./microsoft.gpg /etc/apt/trusted.gpg.d/
    
        sudo apt-get update
    
        sudo apt-get install moby-engine
    
        sudo apt-get install moby-cli
    
        sudo apt-get update
    
        sudo apt-get install iotedge
    
  5. 此時,系統會提示您開啟運行時間組態檔,以插入裝置連接字串,您在 [記事本]) 記下 ([記事本]) 中的 [IoT 中樞 服務] (時,於第 3 章 3) 的步驟 14 中記下。 在終端機上執行下列這一行,以開啟該檔案:

        sudo nano /etc/iotedge/config.yaml
    
  6. config.yaml 檔案隨即顯示,可供您編輯:

    警告

    當此檔案開啟時,可能會有點令人困惑。 您將會在 終端 機本身內編輯此檔案的文字。

    1. 使用鍵盤上的箭頭鍵向下捲動, (您必須向下捲動一點) ,才能到達包含的行::

      <在這裡>新增裝置連接字串」。

    2. 以您稍早記下的裝置連接字串取代行,包括括號

  7. 當您的連接字串就緒時,請在鍵盤上按 Ctrl-X 鍵以儲存盤案。 它會要求您輸入 Y 以確認。然後,按 Enter 鍵以確認。 您將返回一般 終端機

  8. 一旦這些命令都順利執行,您就會安裝 IoT Edge Runtime。 初始化之後,運行時間會在每次裝置開機時自行啟動,並位於背景中,等候模組從 IoT 中樞 服務部署。

  9. 執行下列命令列來初始化 IoT Edge 執行時間

        sudo systemctl restart iotedge
    

    重要

    如果您對 .yaml 檔案或上述安裝程式進行變更,則必須在 終端機內再次執行上述重新啟動行。

  10. 執行下列命令行來檢查 IoT Edge 運行時間狀態。 運行時間應該會以綠色文字顯示狀態為 作用中 (執行)

        sudo systemctl status iotedge
    
  11. Ctrl-C 鍵以結束狀態頁面。 您可以輸入下列命令,確認 IoT Edge 執行時間是否正確提取容器:

        sudo docker ps
    
  12. 應該會出現兩個 (2 個) 容器的清單。 這些是 IoT 中樞 Service (edgeAgent 和 edgeHub) 自動建立的預設模組。 建立及部署自己的模組之後,它們會出現在此清單中,預設模組下方。

第 6 章 - 安裝擴充功能

重要

接下來的章節 (6-9) 將在 Windows 10 計算機上執行。

  1. 開啟 VS Code

  2. 按兩下 VS Code 左側列的 [ 延伸 模組 (方塊) ] 按鈕,以開啟 [ 延伸模組] 面板

  3. 搜尋並安裝下列延伸模組 (,如下圖所示) :

    1. Azure IoT Edge
    2. Azure IoT 工具組
    3. Docker

    顯示延伸模組視窗的螢幕快照。Azure I O T Edge、Azure I O T 工具組和 Docker 會以紅色圓圈。

  4. 安裝擴充功能之後,請關閉並重新開啟 VS Code。

  5. 在 VS Code 再次開啟後,流覽至 [ 檢視>整合式終端機]。

  6. 您現在將會安裝 Cookiecutter。 在終端機中,執行下列bash命令:

        pip install --upgrade --user cookiecutter
    

    [!HINT] 如果您遇到此指令的問題:

    1. 重新啟動 VS Code 和/或您的電腦。
    2. 您可能需要將 VS Code 終端 機切換至您用來安裝 Python 的終端機,也就是 Powershell (特別是在您的電腦上已安裝 Python 環境時) 。 開啟 [終端機] 后,您會在終端機右側找到下拉功能表。 顯示下拉功能表上已選取 1 個 powershell 的螢幕快照。
    3. 請確定已在您的電腦上新增 Python 安裝路徑作為 環境變數 。 Cookiecutter 應該是相同位置路徑的一部分。 如需 環境變數的詳細資訊,請遵循此連結。
  7. 一旦 Cookiecutter 完成安裝,您應該重新啟動電腦,讓 Cookiecutter 在系統的環境中辨識為命令。

第 7 章 - 建立容器解決方案

此時,您必須使用 模組建立容器,才能推送至 Container Registry。 推送容器之後,您將使用 IoT 中樞 Edge 服務將它部署到您的裝置,其執行 IoT Edge 運行時間

  1. 在 VS Code 中,按兩下 [ 檢視>命令選擇區]。

  2. 在調色盤中,搜尋並執行 Azure IoT Edge:新的 Iot Edge 解決方案

  3. 流覽至您要建立解決方案的位置。 按 Enter 鍵以接受位置。

  4. 為您的解決方案命名。 按 Enter 鍵,以確認您提供的名稱。

  5. 現在系統會提示您選擇解決方案的範本架構。 按兩下 [Python 模組]。 按 Enter 鍵以確認這個選擇。

  6. 為您的模組命名。 按 Enter 鍵,以確認模組的名稱。 請務必使用記事本 (記事本) 模組名稱,如稍後使用。

  7. 您會注意到預先建置的 Docker 映像存放庫 地址會出現在調色盤上。 看起來會像這樣:

    localhost:5000/-模組的名稱。

  8. 刪除 localhost:5000,並在其位置插入 Container Registry登入伺服器位址,您在第 2 章) 的步驟 8 中建立 Container Registry Service (時所記下。 按 Enter 鍵以確認位址。

  9. 此時,將會建立包含 Python 模組範本的解決方案,而且其結構會顯示在畫面左側的 [ 探索] 索引標籤 VS Code 中。 如果 [ 探索] 索引 標籤未開啟,您可以在左側列按兩下最上方的按鈕來開啟它。

    顯示 [探索] 索引標籤按鈕的螢幕快照,類似於 2 張堆疊的紙張。

  10. 本章的最後一個步驟是從 [探索] 索引標籤內按兩下並開啟 .env 檔案,然後新增您的 Container Registry使用者名稱和密碼。 Git 會忽略此檔案,但在建置容器時,會將認證設定為存取 Container Registry Service

    顯示命令視窗的螢幕快照,其中顯示第 1 行所輸入的 Container Registry 使用者名稱文字,以及第 2 行輸入的 Container Registry 密碼。

第 8 章 - 編輯容器解決方案

您現在會藉由更新下列檔案來完成容器解決方案:

  • main.py python 腳本。
  • requirements.txt
  • deployment.template.json
  • Dockerfile.amd64

然後,您將建立 python 腳本使用的 images 資料夾,以檢查影像是否符合您的 自訂視覺 模型。 最後,您將新增 labels.txt 檔案,以協助讀取您的模型,以及 model.pb 檔案,也就是您的模型。

  1. 開啟 VS Code 後,流覽至您的模組資料夾,並尋找名為 main.py 的腳本。 按兩下將它開啟。

  2. 刪除檔案的內容,並插入下列程式代碼:

    # Copyright (c) Microsoft. All rights reserved.
    # Licensed under the MIT license. See LICENSE file in the project root for
    # full license information.
    
    import random
    import sched, time
    import sys
    import iothub_client
    from iothub_client import IoTHubModuleClient, IoTHubClientError, IoTHubTransportProvider
    from iothub_client import IoTHubMessage, IoTHubMessageDispositionResult, IoTHubError
    import json
    import os
    import tensorflow as tf
    import os
    from PIL import Image
    import numpy as np
    import cv2
    
    # messageTimeout - the maximum time in milliseconds until a message times out.
    # The timeout period starts at IoTHubModuleClient.send_event_async.
    # By default, messages do not expire.
    MESSAGE_TIMEOUT = 10000
    
    # global counters
    RECEIVE_CALLBACKS = 0
    SEND_CALLBACKS = 0
    
    TEMPERATURE_THRESHOLD = 25
    TWIN_CALLBACKS = 0
    
    # Choose HTTP, AMQP or MQTT as transport protocol.  Currently only MQTT is supported.
    PROTOCOL = IoTHubTransportProvider.MQTT
    
    
    # Callback received when the message that we're forwarding is processed.
    def send_confirmation_callback(message, result, user_context):
        global SEND_CALLBACKS
        print ( "Confirmation[%d] received for message with result = %s" % (user_context, result) )
        map_properties = message.properties()
        key_value_pair = map_properties.get_internals()
        print ( "    Properties: %s" % key_value_pair )
        SEND_CALLBACKS += 1
        print ( "    Total calls confirmed: %d" % SEND_CALLBACKS )
    
    
    def convert_to_opencv(image):
        # RGB -> BGR conversion is performed as well.
        r,g,b = np.array(image).T
        opencv_image = np.array([b,g,r]).transpose()
        return opencv_image
    
    def crop_center(img,cropx,cropy):
        h, w = img.shape[:2]
        startx = w//2-(cropx//2)
        starty = h//2-(cropy//2)
        return img[starty:starty+cropy, startx:startx+cropx]
    
    def resize_down_to_1600_max_dim(image):
        h, w = image.shape[:2]
        if (h < 1600 and w < 1600):
            return image
    
        new_size = (1600 * w // h, 1600) if (h > w) else (1600, 1600 * h // w)
        return cv2.resize(image, new_size, interpolation = cv2.INTER_LINEAR)
    
    def resize_to_256_square(image):
        h, w = image.shape[:2]
        return cv2.resize(image, (256, 256), interpolation = cv2.INTER_LINEAR)
    
    def update_orientation(image):
        exif_orientation_tag = 0x0112
        if hasattr(image, '_getexif'):
            exif = image._getexif()
            if (exif != None and exif_orientation_tag in exif):
                orientation = exif.get(exif_orientation_tag, 1)
                # orientation is 1 based, shift to zero based and flip/transpose based on 0-based values
                orientation -= 1
                if orientation >= 4:
                    image = image.transpose(Image.TRANSPOSE)
                if orientation == 2 or orientation == 3 or orientation == 6 or orientation == 7:
                    image = image.transpose(Image.FLIP_TOP_BOTTOM)
                if orientation == 1 or orientation == 2 or orientation == 5 or orientation == 6:
                    image = image.transpose(Image.FLIP_LEFT_RIGHT)
        return image
    
    
    def analyse(hubManager):
    
        messages_sent = 0;
    
        while True:
            #def send_message():
            print ("Load the model into the project")
            # These names are part of the model and cannot be changed.
            output_layer = 'loss:0'
            input_node = 'Placeholder:0'
    
            graph_def = tf.GraphDef()
            labels = []
    
            labels_filename = "labels.txt"
            filename = "model.pb"
    
            # Import the TF graph
            with tf.gfile.FastGFile(filename, 'rb') as f:
                graph_def.ParseFromString(f.read())
                tf.import_graph_def(graph_def, name='')
    
            # Create a list of labels
            with open(labels_filename, 'rt') as lf:
                for l in lf:
                    labels.append(l.strip())
            print ("Model loaded into the project")
    
            results_dic = dict()
    
            # create the JSON to be sent as a message
            json_message = ''
    
            # Iterate through images 
            print ("List of images to analyse:")
            for file in os.listdir('images'):
                print(file)
    
                image = Image.open("images/" + file)
    
                # Update orientation based on EXIF tags, if the file has orientation info.
                image = update_orientation(image)
    
                # Convert to OpenCV format
                image = convert_to_opencv(image)
    
                # If the image has either w or h greater than 1600 we resize it down respecting
                # aspect ratio such that the largest dimension is 1600
                image = resize_down_to_1600_max_dim(image)
    
                # We next get the largest center square
                h, w = image.shape[:2]
                min_dim = min(w,h)
                max_square_image = crop_center(image, min_dim, min_dim)
    
                # Resize that square down to 256x256
                augmented_image = resize_to_256_square(max_square_image)
    
                # The compact models have a network size of 227x227, the model requires this size.
                network_input_size = 227
    
                # Crop the center for the specified network_input_Size
                augmented_image = crop_center(augmented_image, network_input_size, network_input_size)
    
                try:
                    with tf.Session() as sess:     
                        prob_tensor = sess.graph.get_tensor_by_name(output_layer)
                        predictions, = sess.run(prob_tensor, {input_node: [augmented_image] })
                except Exception as identifier:
                    print ("Identifier error: ", identifier)
    
                print ("Print the highest probability label")
                highest_probability_index = np.argmax(predictions)
                print('FINAL RESULT! Classified as: ' + labels[highest_probability_index])
    
                l = labels[highest_probability_index]
    
                results_dic[file] = l
    
                # Or you can print out all of the results mapping labels to probabilities.
                label_index = 0
                for p in predictions:
                    truncated_probablity = np.float64(round(p,8))
                    print (labels[label_index], truncated_probablity)
                    label_index += 1
    
            print("Results dictionary")
            print(results_dic)
    
            json_message = json.dumps(results_dic)
            print("Json result")
            print(json_message)
    
            # Initialize a new message
            message = IoTHubMessage(bytearray(json_message, 'utf8'))
    
            hubManager.send_event_to_output("output1", message, 0)
    
            messages_sent += 1
            print("Message sent! - Total: " + str(messages_sent))      
            print('----------------------------')
    
            # This is the wait time before repeating the analysis
            # Currently set to 10 seconds
            time.sleep(10)
    
    
    class HubManager(object):
    
        def __init__(
                self,
                protocol=IoTHubTransportProvider.MQTT):
            self.client_protocol = protocol
            self.client = IoTHubModuleClient()
            self.client.create_from_environment(protocol)
    
            # set the time until a message times out
            self.client.set_option("messageTimeout", MESSAGE_TIMEOUT)
    
        # Forwards the message received onto the next stage in the process.
        def forward_event_to_output(self, outputQueueName, event, send_context):
            self.client.send_event_async(
                outputQueueName, event, send_confirmation_callback, send_context)
    
        def send_event_to_output(self, outputQueueName, event, send_context):
            self.client.send_event_async(outputQueueName, event, send_confirmation_callback, send_context)
    
    def main(protocol):
        try:
            hub_manager = HubManager(protocol)
            analyse(hub_manager)
            while True:
                time.sleep(1)
    
        except IoTHubError as iothub_error:
            print ( "Unexpected error %s from IoTHub" % iothub_error )
            return
        except KeyboardInterrupt:
            print ( "IoTHubModuleClient sample stopped" )
    
    if __name__ == '__main__':
        main(PROTOCOL)
    
  3. 開啟名為 requirements.txt的 檔案,並以下列專案取代其內容:

    azure-iothub-device-client==1.4.0.0b3
    opencv-python==3.3.1.11
    tensorflow==1.8.0
    pillow==5.1.0
    
  4. 開啟名為 deployment.template.json 的檔案,並依照下列指導方針取代其內容:

    1. 因為您將有自己的唯一 JSON 結構,所以您必須手動編輯它 (,而不是複製範例) 。 若要簡化此作業,請使用下圖作為指南。

    2. 看起來與您不同的區域,但 您不應該變更的區域會反白顯示黃色

    3. 您需要刪除的區段是醒目提示的紅色。

    4. 請小心刪除正確的括弧,同時移除逗號。

      此螢幕快照顯示代碼行 12 到 15、49 到 57,第 67 行以黃色圓圈。代碼行 39 到 48,第 66 行會以紅色圓圈。

    5. 已完成的 JSON 看起來應該像下圖 (,但您唯一的差異如下: 使用者名稱/密碼/模組名稱/模組參考) :

      顯示命令視窗的螢幕快照,其中已刪除圓形紅色線條。

  5. 開啟名為 Dockerfile.amd64 的檔案,並以下列專案取代其內容:

    FROM ubuntu:xenial
    
    WORKDIR /app
    
    RUN apt-get update && \
        apt-get install -y --no-install-recommends libcurl4-openssl-dev python-pip libboost-python-dev && \
        rm -rf /var/lib/apt/lists/* 
    RUN pip install --upgrade pip
    RUN pip install setuptools
    
    COPY requirements.txt ./
    RUN pip install -r requirements.txt
    
    RUN pip install pillow
    RUN pip install numpy
    
    RUN apt-get update && apt-get install -y \ 
        pkg-config \
        python-dev \ 
        python-opencv \ 
        libopencv-dev \ 
        libav-tools  \ 
        libjpeg-dev \ 
        libpng-dev \ 
        libtiff-dev \ 
        libjasper-dev \ 
        python-numpy \ 
        python-pycurl \ 
        python-opencv
    
    
    RUN pip install opencv-python
    RUN pip install tensorflow
    RUN pip install --upgrade tensorflow
    
    COPY . .
    
    RUN useradd -ms /bin/bash moduleuser
    USER moduleuser
    
    CMD [ "python", "-u", "./main.py" ]
    
    
  6. 以滑鼠右鍵按兩下 模組 底下的資料夾, (它將會有您先前提供的名稱;在範例的下一步中,稱為 pythonmodule) ,然後按兩下 [ 新增資料夾]。 將資料夾 命名為影像

  7. 在資料夾內,新增一些包含滑鼠或鍵盤的影像。 這些是 Tensorflow 模型將分析的影像。

    警告

    如果您使用自己的模型,您必須變更此專案以反映您自己的模型數據。

  8. 您現在必須從模型資料夾擷取 labels.txtmodel.pb檔案,該資料夾先前已下載 (,或從自己的 自訂視覺 Service) 建立。 一旦您擁有檔案,請將這些檔案放在解決方案中,以及其他檔案。 最終結果看起來應該像下圖:

    顯示 [總管] 視窗的螢幕快照。Python 模組資料夾已開啟。

第 9 章 - 將解決方案封裝為容器

  1. 您現在已準備好將檔案「封裝」為容器,並將它推送至您的 Azure Container Registry。 在 VS Code 中,開啟 [整合式終端機] ([檢視>整合式終端機] 或 Ctrl+`) ,然後使用下列這一行登入 Docker (將 命令的值取代為 Azure Container Registry (ACR) ) :

        docker login -u <ACR username> -p <ACR password> <ACR login server>
    
  2. 以滑鼠右鍵按兩下 deployment.template.json 檔案,然後按兩下 [建置 IoT Edge 方案]。 此建置程式需要相當長的時間 (視您的裝置) 而定,因此請準備好等候。 建置程式完成後, deployment.json 檔案將會建立在名為 config 的新資料夾內。

    顯示設定資料夾和部署點 jason 檔案以紅色圓圈的螢幕快照。

  3. 再次開啟 命令選擇區 ,然後搜尋 Azure:登入。 使用您的 Azure 帳戶認證遵循提示;VS Code 會提供 [ 複製] 和 [開啟] 的選項,這會複製您很快就會需要的裝置程序代碼,並開啟您的預設網頁瀏覽器。 當系統詢問時,貼上裝置程式代碼以驗證您的計算機。

    複製並開啟

  4. 登入之後,您會注意到,在 [探索] 面板底部,稱為 [Azure IoT 中樞 裝置] 的新區段。 按兩下此區段加以展開。

    邊緣裝置

  5. 如果您的裝置不在此處,您必須以滑鼠右鍵按兩下 [Azure IoT 中樞 裝置],然後按兩下 [設定 IoT 中樞 連接字串]。 然後您會看到 VS Code) 頂端的 命令 選擇區 (,會提示您輸入 連接字串。 這是您在第 3 章結尾記下的連接字串。 在複製字串之後,請按 Enter 鍵。

  6. 您的裝置應該會載入並出現。 以滑鼠右鍵按兩下裝置名稱,然後按兩下 [ 建立單一裝置的部署]。

    顯示右鍵功能表的螢幕快照。[建立單一裝置的部署] 已醒目提示。

  7. 您將會收到 檔案總管 提示,您可以在其中流覽至 config 資料夾,然後選取 deployment.json 檔案。 選取該檔案后,按兩下 [ 選取Edge部署指令清單] 按鈕。

    顯示 [檔案總管] 視窗的螢幕快照。選取部署點 jason 檔案,選取 [選取 Edge 部署指令清單] 會以紅色圓圈。

  8. 此時,您已為您的 IoT 中樞 服務提供指令清單,以便將容器部署為模組,從您的 Azure Container Registry,有效地將其部署至您的裝置。

  9. 若要檢視從裝置傳送至 IoT 中樞 的訊息,請在 [Azure IoT 中樞 裝置] 區段中的 [裝置] 區段中,以滑鼠右鍵按兩下您的裝置名稱,然後按兩下 [開始監視 D2C 訊息]。 從您的裝置傳送的訊息應該會出現在 VS 終端機中。 請耐心等候,因為這可能需要一些時間。 請參閱下一章以進行偵錯,並檢查部署是否成功。

此課程模組現在會逐一查看 images 資料夾中的影像,並逐一分析它們,並逐一查看每個反覆專案。 這顯然只是示範如何讓基本的機器學習模型在 IoT Edge 裝置環境中運作。

若要擴充此範例的功能,您可以透過數種方式繼續進行。 其中一種方式可能是在容器中包含一些程式代碼、從連線到裝置的網路攝影機擷取相片,並將影像儲存在images資料夾中。

另一種方式是將映像從IoT裝置複製到容器。 若要這樣做,在IoT裝置終端機中執行下列命令的實用方式, (小型應用程式或許可以執行作業,如果您想要將程式自動化) 。 您可以從儲存盤案的資料夾位置手動執行此指令來測試此指令:

    sudo docker cp <filename> <modulename>:/app/images/<a name of your choice>

第 10 章 - 偵錯 IoT Edge 運行時間

以下是命令行和秘訣的清單,可協助您從Ubuntu裝置監視和偵錯 IoT Edge Runtime 的傳訊活動。

  • 執行下列命令列來檢查 IoT Edge 執行時間狀態:

        sudo systemctl status iotedge
    

    注意

    請記得按 Ctrl + C,以完成檢視狀態。

  • 列出目前部署的容器。 如果 IoT 中樞 服務已成功部署容器,則會執行下列命令行來顯示這些容器:

        sudo iotedge list
    

    Or

        sudo docker ps
    

    注意

    上述是檢查模組是否已成功部署的好方法,因為它會出現在清單中;否則 ,您只會 看到 edgeHubedgeAgent

  • 若要顯示容器的程式代碼記錄,請執行下列命令列:

        journalctl -u iotedge
    

用來管理 IoT Edge 執行時間的實用命令:

  • 若要刪除主機中的所有容器:

        sudo docker rm -f $(sudo docker ps -aq)
    
  • 若要停止 IoT Edge 執行時間

        sudo systemctl stop iotedge
    

第 11 章 - 建立數據表服務

流覽回您的 Azure 入口網站,您會在其中建立記憶體資源來建立 Azure 數據表服務。

  1. 如果尚未登入,請登入 Azure 入口網站

  2. 登入之後,按兩下左上角的 [ 建立資源],然後搜尋 記憶體帳戶,然後按 Enter 鍵以開始搜尋。

  3. 出現之後,按兩下清單中的 [記憶體帳戶 - Blob、檔案、資料表、佇列 ]。

    顯示 [新增] 視窗的螢幕快照。儲存空間會在搜尋列中輸入。在 [精選] 底下,儲存體帳戶 Blob、檔案、數據表、佇列會以紅色圓圈。

  4. 新頁面將提供 記憶體帳戶 服務的描述。 在此提示的左下角,按兩下 [ 建立 ] 按鈕,以建立此服務的實例。

    顯示 [記憶體帳戶] 頁面的螢幕快照。頁面底部的 [建立] 按鈕會以紅色圓圈。

  5. 按兩下 [ 建立] 之後,會出現面板:

    1. 針對此服務實例插入所需的 名稱 , (必須是小寫) 。

    2. 針對 [部署模型],按兩下 [資源管理員]。

    3. 針對 [帳戶種類],使用下拉功能表,單擊 [ 記憶體] (一般用途 v1)

    4. 按兩下適當的 [位置]。

    5. 針對 [ 寫] 下拉功能表,單擊 [ 讀取存取-異地備援記憶體] (RA-GRS)

    6. 針對 [效能],按兩下 [標準]。

    7. 在 [ 需要安全傳輸] 區段中,按兩下 [ 已停用]。

    8. 從 [ 訂用帳戶 ] 下拉功能表中,單擊適當的訂用帳戶。

    9. 選擇 資源群組 或建立新的群組。 資源群組可讓您監視、控制存取、布建和管理 Azure 資產集合的計費方式。 建議將所有與單一專案相關聯的 Azure 服務保留 (例如,這些課程) 在通用資源群組) 下。

      如果您想要深入瞭解 Azure 資源群組,請遵循此 連結以瞭解如何管理資源群組

    10. 如果這是選項,請將 [虛擬網络 ] 保留為 [已停用]。

    11. 按一下 [建立]。

      填入記憶體詳細數據

  6. 按兩下 [ 建立] 之後,您必須等候服務建立,這可能需要一分鐘的時間。

  7. 建立服務實例之後,入口網站中會出現通知。 按兩下通知以探索新的服務實例。

    新的記憶體通知

  8. 按兩下通知中的 [ 移至資源 ] 按鈕,系統會帶您前往新的記憶體服務實例概觀頁面。

    顯示部署成功通知的螢幕快照。[移至資源] 按鈕會以紅色圓圈。

  9. 從概觀頁面,按兩下右側的 [ 數據表]。

    表

  10. 右側的面板會變更以顯示 資料表服務 資訊,其中您需要新增數據表。 按兩下左上角的 [+ 資料表 ] 按鈕即可執行此動作。

    開啟數據表

  11. 隨即會顯示新的頁面,其中您需要輸入 數據表名稱。 這是您將在稍後的 Chapters (建立函式應用程式和 Power BI) 中用來參考應用程式中數據的名稱。 將 IoTMessages 插入為名稱, (您可以選擇自己的名稱,只要在此檔稍後使用時加以記住,) 然後按兩下 [ 確定]。

  12. 建立新的數據表之後,您就可以在) 底部的 [ 數據表服務 ] 頁面 (中看到該數據表。

    顯示 [數據表服務] 頁面的螢幕快照,其中列出數據表。

  13. 現在,按兩下 [存取金鑰],並使用記事本) 取得記憶體帳戶名稱和金鑰 (複本,您將在本課程稍後建立 Azure 函式應用程式時使用這些值。

    顯示 [存取金鑰] 頁面的螢幕快照,其位於 [設定] 底下。[儲存體帳戶名稱] 字段和 [金鑰] 欄位會以紅色圓圈。

  14. 再次使用左側面板,捲動至 [ 數據表服務 ] 區段,然後按兩下 [ 資料表 ] (或 [瀏覽數據表],在較新的入口網站中) ,並使用 [記事本] (取得 數據表 URL 複本) 。 您稍後會在將數據表連結至 Power BI 應用程式時,在此課程中使用此值。

    顯示 [數據表服務] 底下 [數據表] 頁面的螢幕快照。I O T 訊息數據表的 U R L 會以紅色圓圈。

第 12 章 - 完成 Azure 數據表

既然已設定 數據表服務 記憶體帳戶,就可以將數據新增至該帳戶,以便用來儲存和擷取資訊。 您可以透過 Visual Studio 編輯資料表。

  1. 開啟 Visual Studio ( Visual Studio Code) 。

  2. 從功能表中,按兩下 [ 檢視>雲端總管]。

    開啟雲端總管

  3. Cloud Explorer 會以停駐專案的形式開啟, (病患,因為載入可能需要) 的時間。

    警告

    如果您用來建立 記憶體帳戶 的訂用帳戶看不到,請確定您具有:

    • 登入與您用於 Azure 入口網站之帳戶相同的帳戶。

    • 從 [帳戶管理] 頁面選取您的訂用帳戶, (您可能需要從您的帳戶設定套用篩選) :

      尋找訂用帳戶

  4. 您的 Azure 雲端服務將會顯示。 尋找 [記憶體帳戶 ],然後按兩下左邊的箭號以展開您的帳戶。

    開啟記憶體帳戶

  5. 展開之後,您應該可以使用新建立的 記憶體帳戶 。 單擊記憶體左邊的箭號,然後展開之後,尋找 [數據表 ],然後按兩下該位置旁的箭號,以顯示您在上一章中建立的 數據表 。 按兩下您的 資料表

  6. 您的數據表將會在 Visual Studio 視窗的中央開啟。 按兩下具有 (加上) 的數據表圖示 +

    新增數據表

  7. 隨即會出現一個視窗,提示您 新增實體。 您只會建立一個實體,但它會有三個屬性。 您會發現已提供 PartitionKeyRowKey ,因為數據表會使用這些索引鍵來尋找您的數據。

    數據分割和數據列索引鍵

  8. 更新下列值:

    • 名稱: PartitionKey,值: PK_IoTMessages

    • 名稱: RowKey、值: RK_1_IoTMessages

  9. 然後,按兩下 [新增實體] 視窗左下方的 [新增屬性 () ,然後新增下列屬性:

    • MessageContent字串,將 Value 保留空白。
  10. 您的資料表應符合下圖中的表格:

    新增正確的值

    注意

    實體在數據列索引鍵中具有數位 1 的原因,是因為您可能想要新增更多訊息,您應該想要進一步實驗本課程。

  11. 完成時按兩下 [ 確定 ]。 您的數據表現在已可供使用。

第 13 章 - 建立 Azure 函式應用程式

現在是時候建立 Azure 函式應用程式IoT 中樞 服務會呼叫此應用程式,以將 IoT Edge 裝置訊息儲存在上一章中建立的數據表服務中。

首先,您需要建立一個檔案,讓您的 Azure 函式能夠載入所需的連結庫。

  1. 開啟 [記事本 ] (按 Windows 鍵,然後輸入 記事本) 。

    開啟記事本

  2. 在 [記事本] 開啟時,將下面的 JSON 結構插入其中。 完成後,請將它儲存在您的桌面上作為 project.json。 此檔案會定義函式將使用的連結庫。 如果您已使用 NuGet,它看起來會很熟悉。

    警告

    命名正確很重要;請確定它 沒有 .txt 擴展名。 請參閱下方以取得參考:

    JSON 儲存

    {
    "frameworks": {
        "net46":{
        "dependencies": {
            "WindowsAzure.Storage": "9.2.0"
        }
        }
    }
    }
    
  3. 登入 Azure 入口網站

  4. 登入之後,按兩下左上角的 [ 建立資源 ],然後搜尋 函式應用程式,然後按 Enter 鍵進行搜尋。 從結果按兩下 [ 函式應用程式 ],以開啟新的面板。

    搜尋函式應用程式

  5. 新的面板將提供 函式App Service的描述。 在此面板左下方,按兩下 [ 建立 ] 按鈕,以建立與此服務的關聯。

    函式應用程式實例

  6. 按兩下 [ 建立] 之後,請填寫下列內容:

    1. 針對 [應用程式名稱],插入此服務實例所需的名稱。

    2. 選取 [訂用帳戶] 。

    3. 選取適合您的定價層,如果這是第一次建立函式 App Service,則免費層應該可供您使用。

    4. 選擇 資源群組 或建立新的群組。 資源群組可讓您監視、控制存取、布建和管理 Azure 資產集合的計費方式。 建議將所有與單一專案相關聯的 Azure 服務保留 (例如,這些課程) 在通用資源群組) 下。

      如果您想要深入瞭解 Azure 資源群組,請遵循此 連結以瞭解如何管理資源群組

    5. 針對 [操作系統],按兩下 [Windows],如同預期平臺一樣。

    6. (本教學 課程 使用取用方案,請選取主 控方案

    7. 選取 位置 (選擇與您在上一個步驟中建置的記憶體相同的位置)

    8. 針對 [ 記憶體 ] 區段, 您必須選取您在上一個步驟中建立的記憶體服務

    9. 您不需要此應用程式中的 Application Insights ,因此請放心地將其 關閉

    10. 按一下 [建立]。

      建立新的實例

  7. 按兩下 [ 建立] 之後,您必須等候服務建立,這可能需要一分鐘的時間。

  8. 建立服務實例之後,入口網站中會出現通知。

    新增通知

  9. 按兩下通知,一旦部署成功, (完成) 。

  10. 按兩下通知中的 [ 移至資源 ] 按鈕,以探索新的服務實例。

    顯示 [部署成功通知] 視窗的螢幕快照。[移至資源] 按鈕會以紅色圓圈。

  11. 在新面板的左側,按兩下 + [ 式] 旁的 (加上) 圖示,以建立新的函式。

    顯示 [函式應用程式] 頁面的螢幕快照。在 Functions 旁邊的左側功能表中,加號會以紅色圓圈。

  12. 在中央面板中,[ 式建立] 視窗隨即出現。 進一步向下卷動,然後按兩下 [自定義函式]。

    顯示 [函式建立] 視窗底部的螢幕快照。自定義函式會以紅色圓圈。

  13. 向下捲動下一頁,直到您找到 IoT 中樞 (事件中樞) ,然後按兩下它。

    顯示 [I O T 中樞事件中樞] 方塊以紅色圓圈的螢幕快照。

  14. [IoT 中樞 (事件中樞) ] 刀鋒視窗中,將 [語言] 設定為 C# ,然後按兩下 [新增]。

    顯示 [新增函式] 頁面的螢幕快照。在 [語言] 欄位中選取 C sharp。[事件中樞連線] 選項旁的 [新增] 會以紅色圓圈。

  15. 在出現的視窗中,確定已選取 [IoT 中樞],且 [IoT 中樞] 欄位的名稱會與您先前在步驟 3) 的步驟 8 中建立 (IoT 中樞 服務的名稱相對應。 然後按下 [ 選取] 按鈕。

    顯示 [I O T 中樞] 索引標籤開啟的螢幕快照。I O T 中樞和端點字段會以紅色圓圈。

  16. 回到 [IoT 中樞 (事件中樞) ] 刀鋒視窗,按兩下 [建立]。

    顯示 [新增函式] 頁面的螢幕快照。[建立] 按鈕會以紅色圓圈在頁面底部。

  17. 系統會將您重新導向至函式編輯器。

    顯示函式編輯器頁面的螢幕快照。函式會在左側功能表中選取。

  18. 刪除其中的所有程式代碼,並將其取代為下列內容:

    #r "Microsoft.WindowsAzure.Storage"
    #r "NewtonSoft.Json"
    
    using System;
    using Microsoft.WindowsAzure.Storage;
    using Microsoft.WindowsAzure.Storage.Table;
    using Newtonsoft.Json;
    using System.Threading.Tasks;
    
    public static async Task Run(string myIoTHubMessage, TraceWriter log)
    {
        log.Info($"C# IoT Hub trigger function processed a message: {myIoTHubMessage}");
    
        //RowKey of the table object to be changed
        string tableName = "IoTMessages";
        string tableURL = "https://iothubmrstorage.table.core.windows.net/IoTMessages";
    
        // If you did not name your Storage Service as suggested in the course, change the name here with the one you chose.
        string storageAccountName = "iotedgestor"; 
    
        string storageAccountKey = "<Insert your Storage Key here>";   
    
        string partitionKey = "PK_IoTMessages";
        string rowKey = "RK_1_IoTMessages";
    
        Microsoft.WindowsAzure.Storage.Auth.StorageCredentials storageCredentials =
            new Microsoft.WindowsAzure.Storage.Auth.StorageCredentials(storageAccountName, storageAccountKey);
    
        CloudStorageAccount storageAccount = new CloudStorageAccount(storageCredentials, true);
    
        // Create the table client.
        CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
    
        // Get a reference to a table named "IoTMessages"
        CloudTable messageTable = tableClient.GetTableReference(tableName);
    
        //Retrieve the table object by its RowKey
        TableOperation operation = TableOperation.Retrieve<MessageEntity>(partitionKey, rowKey);
        TableResult result = await messageTable.ExecuteAsync(operation);
    
        //Create a MessageEntity so to set its parameters
        MessageEntity messageEntity = (MessageEntity)result.Result;
    
        messageEntity.MessageContent = myIoTHubMessage;
        messageEntity.PartitionKey = partitionKey;
        messageEntity.RowKey = rowKey;
    
        //Replace the table appropriate table Entity with the value of the MessageEntity Ccass structure.
        operation = TableOperation.Replace(messageEntity);
    
        // Execute the insert operation.
        await messageTable.ExecuteAsync(operation);
    }
    
    // This MessageEntity structure which will represent a Table Entity
    public class MessageEntity : TableEntity
    {
        public string Type { get; set; }
        public string MessageContent { get; set; }   
    }
    
  19. 變更下列變數,使其分別對應至第 11 章) 的步驟 11 和 13 中的適當值 (數據表記憶體值:

    • tableName,具有您儲存體帳戶數據表的名稱。
    • tableURL,其中含有您記憶體帳戶數據表的 URL。
    • storageAccountName,其值名稱對應至記憶體 帳戶 名稱。
    • storageAccountKey,其中包含您先前在記憶體服務中取得的密鑰。

    顯示命令提示字元的螢幕快照。第 15、16、19 和 21 行會以紅色圓圈。

  20. 就地執行程式代碼后,按兩下 [ 儲存]。

  21. 接下來,按下 < 頁面右側 (箭號) 圖示。

    顯示 [函式應用程式] 頁面的螢幕快照。

  22. 面板會從右側滑入。 在該面板中,按兩下 [ 上傳],[ 檔案瀏覽器 ] 隨即出現。

  23. 流覽至 ,然後按下您先前在 [記事本] 中建立的 project.json 檔案,然後按兩下 [開啟] 按鈕。 此檔案會定義函式將使用的連結庫。

    此螢幕快照顯示 [檢視檔案] 底下的紅色圓形上傳按鈕。在 [檔案瀏覽器] 中,已選取專案點 jason。

  24. 檔案上傳後,它會出現在右側的面板中。 按兩下會在 函式 編輯器開啟它。 它看起來必須與下一個影像 完全相同

    顯示 [函式應用程式] 頁面的螢幕快照。在左側功能表中整合會以紅色圓圈。

  25. 此時,最好測試函式的功能,以將訊息儲存在 數據表上。 在視窗右上方,按兩下 [ 測試]。

    顯示 [函式應用程式] 頁面的螢幕快照。在右上角進行測試,左下角的 [執行] 按鈕會以紅色圓圈。

  26. 要求本文上插入訊息,如上圖所示,然後按兩下 [ 執行]。

  27. 函式將會執行,並顯示結果狀態 (您會注意到 [輸出] 視窗上方的綠色 [已接受狀態 202],這表示它是成功的呼叫) :

    輸出結果

第 14 章 - 檢視使用中的訊息

如果您現在開啟 Visual Studio ( Visual Studio Code) ,您可以將測試訊息結果可視化,因為它會儲存在 MessageContent 字串區域中。

顯示 Microsoft Visual Studio 中開啟 [I O T 訊息數據表] 索引標籤的螢幕快照。

有了數據表服務和函式應用程式,您的 Ubuntu 裝置訊息會出現在 IoTMessages 資料表中。 如果尚未執行,請再次啟動您的裝置,而且您將能夠透過使用 Visual Studio Cloud Explorer,從您的裝置和模組查看來自裝置的結果訊息,以及模組。

可視化數據

第 15 章 - Power BI 設定

若要將 IOT 裝置中的數據可視化,您將設定 Power BI (桌面版本) ,以從您剛才建立的 數據表 服務收集數據。 Power BI 的 HoloLens 版本接著會使用該數據將結果可視化。

  1. 開啟 Windows 10 上的 Microsoft Store 並搜尋 Power BI Desktop

    顯示 Microsoft Store 視窗的螢幕快照。Power B I 會在搜尋列中輸入,Power B I Desktop 會以紅色圓圈。

  2. 下載應用程式。 下載完成之後,請開啟它。

  3. 使用您的 Microsoft 365 帳戶登入 Power BI。 您可能會重新導向至瀏覽器,以註冊。 註冊之後,請返回 Power BI 應用程式,然後再次登入。

  4. 按兩下 [ 取得數據 ],然後按兩下 [ 更多...]。

    顯示Power B I Desktop 的螢幕快照。[取得數據] 下拉功能表中的 [更多] 會以紅色圓圈。

  5. 按兩下 [Azure]、 [Azure 資料表記憶體],然後按兩下 [ 連線]。

    顯示 [取得資料] 視窗的螢幕快照。Azure 資料表記憶體是在 [Azure] 選單選項中選取。右下角的 [連接] 按鈕會以紅色圓圈。

  6. 系統會提示您在建立數據表服務時,於第 11 章 (第 11 章的步驟 13 中插入您先前收集的數據表 URL) 。 插入 URL 之後,請在此課程中,刪除參考 「數據表」子資料夾 (部分,也就是 IoTMessages) 。 最終結果應該如下圖所示。 接著按一下 [確定]。

    顯示 [Azure 資料表記憶體] 對話框的螢幕快照。U R L 會在 [帳戶名稱] 或 [U R L] 字段中輸入。

  7. 系統會提示您在建立資料表記憶體時,於稍早第 11 章的步驟 1) 1 中插入您記下 (的記憶體密鑰。 然後按兩下 [ 連線]。

    顯示 Azure 資料表記憶體帳戶金鑰頁面的螢幕快照。

  8. [ 導覽器面板 ] 隨即顯示,勾選 [數據表] 旁的方塊,然後按兩下 [ 載入]。

    顯示 [導覽器] 面板的螢幕快照。已核取 I O T 訊息檔案旁的方塊。

  9. 您的數據表現在已載入 Power BI,但需要查詢來顯示其中的值。 若要這樣做,請以滑鼠右鍵按下位於畫面右側 [ 字段] 面板 的數據表名稱。 然後按兩下 [ 編輯查詢]。

    顯示 [欄位] 面板的螢幕快照。[I O T 訊息] 右鍵功能表中的 [編輯查詢] 會以紅色圓圈。

  10. Power Query 編輯器 會開啟為新的視窗,並顯示您的資料表。 按兩下資料表 [內容] 資料行內的 [記錄] 一詞,以可視化方式呈現儲存的內容。

    顯示 [Power Query 編輯器] 視窗的螢幕快照。在 [內容] 底下,[記錄] 會以紅色圓圈。

  11. 按兩下視窗左上方的 [ 進入資料表]。

    顯示 [轉換] 索引標籤 Power Query 編輯器 的螢幕快照。在左上角,[進入數據表] 會以紅色圓圈。

  12. 按兩下 [ 關閉 & 套用]。

    顯示 Power Query 編輯器 中 [首頁] 索引標籤的螢幕快照。關閉並套用會以紅色圓圈。

  13. 一旦查詢完成載入之後,請在 [字段] 面板的畫面右側,勾選對應至 [ 名稱 ] 和 [ ] 參數的方塊,以可視化 顯示 MessageContent 數據行內容。

    顯示 [欄位] 面板的螢幕快照。在 [I O T 訊息] 底下,會核取 [名稱] 和 [值]。[名稱] 和 [值] 資料行的彈出視窗會以紅色圓圈。

  14. 按兩下視窗左上方的 藍色磁碟圖示 ,將工作儲存在您選擇的資料夾中。

    顯示Power B I Desktop 的螢幕快照。左上角的藍色磁碟會以紅色圓圈。[另存新檔] 對話框隨即開啟,而 [儲存] 按鈕會以紅色圓圈。

  15. 您現在可以按兩下 [發佈] 按鈕,將您的資料表上傳至工作區。 出現提示時,按兩下 [我的工作區 ],然後按兩下 [ 選取]。 等候它顯示提交的成功結果。

    此螢幕快照顯示 [發佈] 圓圈以紅色圈狀顯示。在 [發佈至 Power B I] 對話框中,已選取 [選取目的地] 底下的 [我的工作區]。

    顯示通知的螢幕快照,指出發佈至 Power B 我成功。

警告

下列章節是 HoloLens 專屬的。 Power BI 目前無法作為沈浸式應用程式,不過,您可以透過傳統型應用程式,在 Windows Mixed Reality 入口網站中執行桌面版本, (也稱為 一般) 。

第 16 章 - 在 HoloLens 上顯示 Power BI 數據

  1. 在您的 HoloLens 上,點選應用程式清單中的圖示來登入 Microsoft Store

    Holo Lens 顯示器,顯示導覽視窗中 Microsoft Store 圖示周圍的紅色圓圈。

  2. 搜尋並下載 Power BI 應用程式。

    顯示 Microsoft Store 頁面的 Holo Lens 顯示器。已選取 [捲動工具],並在搜尋列中輸入電源 B。

  3. 從您的應用程式清單中啟動 Power BI

  4. Power BI 可能會要求您登入 您的 Microsoft 365 帳戶

  5. 在應用程式內之後,工作區預設會顯示,如下圖所示。 如果沒有發生這種情況,只要按兩下視窗左側的工作區圖示即可。

    Holo Lens 顯示 Microsoft Power B I 頁面。拖曳工具已選取頂端。類似圖形的工作區圖示會以紅色圓圈。[報表] 下方的 [I O T Edge 數據表] 會以紅色圓圈。

您已完成 IoT 中樞 應用程式

恭喜,您已成功建立具有模擬虛擬機 Edge 裝置的 IoT 中樞 服務。 您的裝置可以將機器學習模型的結果傳達至 Azure 資料表服務,由 Azure 函式應用程式所促進,該應用程式會讀取 Power BI,並在 Microsoft HoloLens 內可視化。

Holo Lens 顯示 Microsoft Power B I 頁面。

額外練習

練習 1

展開儲存在數據表中的傳訊結構,並將其顯示為圖形。 您可能想要收集更多數據,並將其儲存在相同的數據表中,以供稍後顯示。

練習 2

建立額外的「相機擷取」模組,以部署在IoT面板上,以便透過要分析的相機擷取影像。