Intelligent Technology's Technical Blog

株式会社インテリジェントテクノロジーの技術情報ブログです。

エッジコンピューティング用プラットフォーム『EdgeX Foundry』を体験する

こんにちは、松村剛です
スマートグリッドが注目を集めた頃から、IoT関連のシステムに興味を持っていたのですが、今回、エッジコンピューティングのためのプラットフォームに実際に動かしてみたいと思います。

エッジコンピューティングのプラットフォームも以前に比べて増え、AWSにもエッジ向けのサービスがありますが、今回は過去に少し触れたEdgeXをターゲットにします。

EdgeXについて

googleで「EdgeX」と検索をして、ヒットする日本語の記事は少ないので知らない方も多いかと思うので、EdgeXについて簡単に説明します。

EdgeXはエッジコンピューティング用にマイクロサービスで構成されたプラットフォームです。

エッジコンピューティングはデバイスなどの機器が持つデータを

  1. 収集して
  2. 解析・加工して
  3. サーバに送る

というような処理を行い、サーバ側の負荷や通信量の抑止をする役割があります。

EdgeXでは

  1. デバイスからのデータ受信・蓄積
  2. 簡易なデータ解析(フィルタリングなど)
  3. サーバへの転送

を行う仕組みを提供しています。
加えてセキュリティ通信を行う仕組みやサーバからデバイスへ指示を伝える機能などもあります。
これら提供されている機能と連携して、より詳細なデータ分析・加工処理を行うサービスを作成することで目的に合わせたエッジコンピューティングを作ることになります。

詳細に関しては以下のEdgeXのURLを読んでいただければと思います。
英語で結構な量があり、バージョン毎の内容が混在しているものもあるのでちゃんと読み込もうとするとそれなりの時間がかかりますが…
www.edgexfoundry.org

最低限、以下の2つの図を最初に見ておくこととEdgeXはどんなものか理解しやすくなると思います。

https://www.edgexfoundry.org/cmsfiles/image/Platform/edgex-platform-architecture-2.jpg
EdgeX Foundry Architecture
https://www.edgexfoundry.org/cmsfiles/image/Platform/edgex-platform-architecture-2.jpg

https://www.edgexfoundry.org/cmsfiles/image/Platform/edgex-focused-at-the-iot-edge-2.jpg
EdgeX Foundry Project Scope
https://www.edgexfoundry.org/cmsfiles/image/Platform/edgex-focused-at-the-iot-edge-2.jpg

ハード・OSを選ばないことを目標にして作られており、実行環境の構築に関してはDockerを使うか、Linuxであればsnapsを使うこともできます。

EdgeXについての概要はここまでで

今回やりたいこと

EdgeXの基本機能であるデバイスの情報を保持してそれをサーバに送信するというところまでを体験したいと思います。

そのための環境としては以下

  • 自宅のPC(EdgeXの操作およびサーバアプリ相当)
  • ラズパイ4(EdgeXが動作する環境相当)

EdgeXプラットフォームの構築はDockerで作成します。

ラズパイ4上でEdgeXを起動させる

EdgeX用環境準備

使用するラズパイ4のスペックは以下。

項目 内容
CPU aarch64/Cortex-A72/1800MHz/4コア
メモリ 8GB
OS ubuntu20.04

ラズパイ3を使いたいところですが、2022年8月現在は入手困難なのでラズパイ4を。
下手なPCより高スペックです…

構築にはDockerを使用するので、最低限必要なのソフトウェアは以下。

  • docker
  • docker-compose
  • git

※実際には、この後説明する「セキュリティ有り」での画面表示のためにもう少しインストールしましたが、やりたいことに対してはこの程度で大丈夫です。

EdgeXを動かすためのDockerファイルはGitHub上にあります
https://github.com/edgexfoundry/edgex-compose

GitHubから上記のレポジトリをcloneすると次の観点で用意されたDockerファイルが取得できます。

  • CPUアーキテクチャ(arm64/x86_x64)
  • セキュリティの有無
  • サンプルのApplicationサービスの有無

今回はラズパイ4上で動かすのでCPUは「arm64」で、セキュリティ無し、サンプルのApplicationサービスが含まれる『docker-compose-no-security-with-app-sample-arm64.yml』を使用します。
また、使用するバージョンは2022年8月にリリースされた最新バージョンの「kamakura」を使いたいので、ブランチをそちらにcheckoutしておきます。

EdgeXプラットフォームの起動

docker-compose-no-security-with-app-sample-arm64.ymlを使うと以下のコンテナが起動します。

起動コンテナ

EdgeXのプロジェクト内で作成されたサービス以外にも

  • サービス・定義を管理する『consul』
  • データ管理:イベント管理をする『redis』
  • Edge内でのイベントルールを管理する『kuiper』

など、他のOSSを使ってサービスが提供していることがわかります

なお、セキュリティ有りのdocker-compose-with-app-sample-arm64.ymlで起動するコンテナは以下です。

起動コンテナ(セキュリティ有)

セキュリティ無しと比べて、『vault』と『kong』などセキュリティを担うサービスが動作しているのがわかります。

EdgeXプラットフォームへのアクセス

EdgeXが起動したら、EdgeXの状態をPC上から確認するためにブラウザからアクセスします。
ブラウザからのアクセス対象になるのは以下の2つ

対象 ポート番号 内容
consal画面 8500 プラットフォーム管理をしているconsulが提供している画面
EdgeX-UI画面 4000 EdgeXが提供しているサービスなどの設定変更や状態確認ができる画面

EdgeX-UI画面用のポートはデフォルトで公開ポートとなっています(開発時での使用およびデモンストレーションが目的の画面のため)。

一方のconsulが提供している画面へのポートはローカルのみとなっています。
動かすことが目的であればEdgeX-UI画面にアクセスできれば事足りますが、せっかくなのでconsulにもアクセスできるようにdockerファイルを修正します

@@ -122,7 +122,7 @@ services:
     networks:
       edgex-network: {}
     ports:
-    - 127.0.0.1:8500:8500/tcp
+    - 8500:8500/tcp
     read_only: true
     restart: always

Dockerファイル修正後、再度起動してPCからラズパイ4の8500ポートにアクセスすると以下の画面が表示されます。

consul画面

各項目で以下のことが行えます。

  • Serviceではアクセスしたconsalが管理しているサービス群の確認
  • Nodeでは各サービスプロセスの死活監視
  • Key/Valueではサービスのプロパティ情報の参照・操作

cunsalの役割はEdgeXプラットフォーム内の各サービスの管理なのでEdgeXを動かすための設定変更はプロパティの変更程度になります。
画面上、他の項目もありますが、セキュリティ無しで起動しているので参照できません。

なお、セキュリティ有りで起動すると以下のようにログインが必要になります。

consal画面(セキュリティ有)
デバイスから送信されるデータの確認

起動させたDockerファイルでは「edgex-device-virtual」という仮想デバイス(テスト用のMockデバイスプロセス)も立ち上がり、データの送信が行われます。
このデータはEdgeX-UIから確認可能です。
EdgeX-UI画面は前述の表のとおり、ブラウザから4000番ポートからのアクセスになります。

EdgeX-UI画面

仮想デバイスからのデータを確認するのは「DataCenter」になります。

DataCenter(イベント表示)

Eventタブではデバイスが送ってきた値を含む以下の通知を1レコードずつ表示しています。

  {
    "apiVersion": "v2",
    "id": "8135b336-5d8e-4702-b5a6-a29b010cd5ee",
    "deviceName": "Random-Integer-Device",
    "profileName": "Random-Integer-Device",
    "sourceName": "Int8",
    "origin": 1661295718311342600,
    "readings": [
      {
        "id": "59eff79b-9828-49f6-8701-bb93a6aed4b5",
        "origin": 1661295718311342600,
        "deviceName": "Random-Integer-Device",
        "resourceName": "Int8",
        "profileName": "Random-Integer-Device",
        "valueType": "Int8",
        "value": "77"
      }
    ]
  }

「Reading」タブは上記のreading属性の値のみが表示されています。
reading属性はapiVersion属性が無い代わりに、デバイスからの測定値である「value」が含まれています
※動作している仮想デバイスではランダムな数値を設定して送っています。

「DataCenter」の表示は3秒ごとにデータを格納しているredisからデータ取得するので、実際に仮想デバイスからの通知タイミングとはリンクしていません。
仮想デバイス側はデフォルトでは10~15秒のインターバルで通知を行っているので、同じ通知が複数回表示されることがあります。
あくまでも開発・デモンストレーション用なのでデバイスから通知に反応するViewが欲しい場合は自分で作ることになるでしょう。

データのExport

ここまでで、

  • EdgeXのプラットフォームが動作していること
  • MockのDeviceからのデータが受信できていること

は確認できました。

次はEdgeXからサーバにデータを送信(Export)させます。

データのExportはサンプルとして提供されているアプリケーションサービス層にある「app-sample」を使用します。

AppServiceトップ画面

一覧にある「app-sample」の「Configurable」ボタンを押すと該当のサービスがが提供するExport用Pipelineの一覧が表示されます。
名前は違いますが、実行できる処理はどれも同じなので「default-pipeline」を編集してExportを設定を行います。
データを送信するタイミングに関しては「trigger」で定義できますが、こちらはデフォルトのredisへのPublishが行われた時のままにします。

app-sampleのPipeline一覧画面

EdegX-UIを使ってのPipelineの設定は

  1. 「Builtin Pipeline Functions」のPipelineとして実行できる処理を示した各タグをドラック&ドロップで「Func Execution Order」に持っていく
  2. 「Pipeline Functions Parameter Setting」にその処理のセッティングエリアが追加されるので設定を行う

という作業で行うことでできます。

今回の「app-sample」では
青線で記しているのがPieplineとして実行できる処理
赤線で記しているのが「default-pipeline」が実行するpipelineの処理順序(とその設定内容)」
となります

Pipeline設定画面

Pipelineから処理を削除したい場合は「Pipeline Functions Parameter Setting」エリアにある各機能のごみ箱ボタンを使って消せます。

「default-pipeline」の初期設定では
データのフィルタリングとして

  • プロファイル名
  • デバイス名
  • 送信するデータのリソース名

フィルタリングされたデータを

  • XMLフォーマットへの変換

最後にレスポンスデータ型を

  • application/xmlで受ける設定にする

という定義になっています。

この定義ではデータのExportは行われないので、HTTPプロトコルでデータのExportをする「HTTPExport」を追加します。

あて先は自宅のPC上で動作するSpringBootでとします。

あて先に関する設定情報
IPアドレス:サーバのあるマシンのIPアドレス(今回は192.168.0.26)
ポート:WebアプリのListenポート(今回は8080)
パス:/demo/recieve

リクエストを受けるSpringBootのController実装は以下です。
受け取った電文をそのまま表示するだけです。

package sample.spring.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.context.annotation.Scope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Scope("request")
@RequestMapping("/demo")
public class deomController {

    @GetMapping("/ping")
    public String ping() {
        System.out.println("*** called ping");
        return "OK";
    }
    @PostMapping("/recieve")
    public String recieve(final HttpServletRequest req, @RequestBody String body) {
        System.out.println("Receive Data : " + body);
        return "OK";
    }
}

この情報を使用してExport処理が行える「HttpExport」を「Func Execution Order」へドラック&ドロップして実行リストに登録。
「Pipeline Functions Parameter Setting」エリアに表示された「HTTPExport」のパラメタ設定エリアのURLに前述の情報を設定後、一番上にある「Save」ボタンを押すと設定した定義でPieplineが動き出します。

Func Execution Orderの設定
HTTPExportの設定

SpringBootのアプリはEdteX-UIの「DataCenter」で表示されていた内容がXMLフォーマットに変換されたものを受信します

Receive Data : <Event><ApiVersion>v2</ApiVersion><Id>f01416fb-29ac-4b5e-91e0-39da94eff86e</Id><DeviceName>Random-Integer-Device</DeviceName><ProfileName>Random-Integer-Device</ProfileName><SourceName>Int64</SourceName><Origin>1661236550596954051</Origin><Readings><Id>462b5d41-057e-48bd-8006-6c65328140e7</Id><Origin>1661236550596954051</Origin><DeviceName>Random-Integer-Device</DeviceName><ResourceName>Int64</ResourceName><ProfileName>Random-Integer-Device</ProfileName><ValueType>Int64</ValueType><Units></Units><BinaryValue></BinaryValue><MediaType></MediaType><Value>-5774734313394839914</Value></Readings></Event>
Receive Data : <Event><ApiVersion>v2</ApiVersion><Id>79132ed8-21ef-43c5-81db-19d6deeea393</Id><DeviceName>Random-Integer-Device</DeviceName><ProfileName>Random-Integer-Device</ProfileName><SourceName>Int16</SourceName><Origin>1661236550592741574</Origin><Readings><Id>f0c354e3-49f1-4639-9fcf-a9c782eb059b</Id><Origin>1661236550592741574</Origin><DeviceName>Random-Integer-Device</DeviceName><ResourceName>Int16</ResourceName><ProfileName>Random-Integer-Device</ProfileName><ValueType>Int16</ValueType><Units></Units><BinaryValue></BinaryValue><MediaType></MediaType><Value>-27298</Value></Readings></Event>
Receive Data : <Event><ApiVersion>v2</ApiVersion><Id>f5d2e805-f5d1-4d21-bbdb-24a2aa2b43f2</Id><DeviceName>Random-Integer-Device</DeviceName><ProfileName>Random-Integer-Device</ProfileName><SourceName>Int8</SourceName><Origin>1661236550592967941</Origin><Readings><Id>4aaa4155-3a1a-4fac-92ab-6a65f29a24ea</Id><Origin>1661236550592967941</Origin><DeviceName>Random-Integer-Device</DeviceName><ResourceName>Int8</ResourceName><ProfileName>Random-Integer-Device</ProfileName><ValueType>Int8</ValueType><Units></Units><BinaryValue></BinaryValue><MediaType></MediaType><Value>106</Value></Readings></Event>
Receive Data : <Event><ApiVersion>v2</ApiVersion><Id>e2ba45cb-7cac-45f4-b4e0-f8b45ec7c645</Id><DeviceName>Random-Integer-Device</DeviceName><ProfileName>Random-Integer-Device</ProfileName><SourceName>Int32</SourceName><Origin>1661236550592866776</Origin><Readings><Id>c8cf1d8d-9102-40d3-b72a-80cc5d6af7b9</Id><Origin>1661236550592866776</Origin><DeviceName>Random-Integer-Device</DeviceName><ResourceName>Int32</ResourceName><ProfileName>Random-Integer-Device</ProfileName><ValueType>Int32</ValueType><Units></Units><BinaryValue></BinaryValue><MediaType></MediaType><Value>407548539</Value></Readings></Event>

ここからEdgeX-UI側で「TransformXml」を削除すると受信するデータはJsonフォーマットに変わります。

Receive Data : {"apiVersion":"v2","id":"c0b9908b-5d8f-4561-bd63-7f962df27d79","deviceName":"Random-Integer-Device","profileName":"Random-Integer-Device","sourceName":"Int8","origin":1661237345674290707,"readings":[{"id":"89622275-e8a8-4c53-b52c-829de9ffb64b","origin":1661237345674290707,"deviceName":"Random-Integer-Device","resourceName":"Int8","profileName":"Random-Integer-Device","valueType":"Int8","value":"80"}]}
Receive Data : {"apiVersion":"v2","id":"7117a123-22fd-472c-af85-cbc1b24ef601","deviceName":"Random-Integer-Device","profileName":"Random-Integer-Device","sourceName":"Int32","origin":1661237345674038729,"readings":[{"id":"f7d6ff83-1b9e-4289-b1e0-da96f7f0adb8","origin":1661237345674038729,"deviceName":"Random-Integer-Device","resourceName":"Int32","profileName":"Random-Integer-Device","valueType":"Int32","value":"1524864640"}]}
Receive Data : {"apiVersion":"v2","id":"797f7fe3-82e8-48f8-b879-3c1863287fb3","deviceName":"Random-Integer-Device","profileName":"Random-Integer-Device","sourceName":"Int16","origin":1661237345673591920,"readings":[{"id":"c756a6ef-d903-41f9-8527-5e4ad694723a","origin":1661237345673591920,"deviceName":"Random-Integer-Device","resourceName":"Int16","profileName":"Random-Integer-Device","valueType":"Int16","value":"9916"}]}
Receive Data : {"apiVersion":"v2","id":"197df3e6-2dcc-4a36-ba77-cb27f2c9c2b2","deviceName":"Random-Integer-Device","profileName":"Random-Integer-Device","sourceName":"Int64","origin":1661237345684589087,"readings":[{"id":"ba96ae58-5724-4482-816c-6e4ad8e20c98","origin":1661237345684589087,"deviceName":"Random-Integer-Device","resourceName":"Int64","profileName":"Random-Integer-Device","valueType":"Int64","value":"8393054513714800417"}]}

さらに「FilterByResourceName」で「Int8, Int64」に変更するとInt16とInt32のデータはExportされなくなります

Receive Data : {"apiVersion":"v2","id":"3c6d1ac3-0d8a-4f6d-a42f-4b1a2fb96f70","deviceName":"Random-Integer-Device","profileName":"Random-Integer-Device","sourceName":"Int8","origin":1661237570700300663,"readings":[{"id":"144d0274-d071-4c42-92b3-b547c442118b","origin":1661237570700300663,"deviceName":"Random-Integer-Device","resourceName":"Int8","profileName":"Random-Integer-Device","valueType":"Int8","value":"104"}]}
Receive Data : {"apiVersion":"v2","id":"b87e5cbd-6c51-4aa5-8ac3-fbe7ffe3a1f7","deviceName":"Random-Integer-Device","profileName":"Random-Integer-Device","sourceName":"Int64","origin":1661237570707968856,"readings":[{"id":"b673b9ab-7b92-42a9-b5da-27e570163f7c","origin":1661237570707968856,"deviceName":"Random-Integer-Device","resourceName":"Int64","profileName":"Random-Integer-Device","valueType":"Int64","value":"-4733742836713686468"}]}

さらにさらに「batch」タグを追加(※フィルタリング処理の後に追加する必要あり)し、下記のような設定を行うと指定した間隔でデータを一括で送信します。
ただし、このbatch機能を使用するとEdgeXからExportされるデータはbyte配列になるため、SpirngBootのControllerメソッドに変更が必要になります。

batch設定

上記設定によるSpringBootで受信するデータは以下の通り。
60秒間隔で受け取り、1回の送信データ内に複数のデータが含まれる形になります。

[Wed Aug 24 11:30:09 JST 2022]Receive Data : [{"apiVersion":"v2","id":"9b2a9a1f-8b79-4861-8e0d-c68bf24382b8","deviceName":"Random-Integer-Device","profileName":"Random-Integer-Device","sourceName":"Int8","origin":1661308185041479566,"readings":[{"id":"2364dfc1-c044-4d2f-8133-2028ddadea29","origin":1661308185041479566,"deviceName":"Random-Integer-Device","resourceName":"Int8","profileName":"Random-Integer-Device","valueType":"Int8","value":"86"}]},{"apiVersion":"v2","id":"f9a30889-1d33-4182-956d-3ec6dbdeb323","deviceName":"Random-Integer-Device","profileName":"Random-Integer-Device","sourceName":"Int64","origin":1661308185042176577,"readings":[{"id":"c63ba342-0983-435f-ba23-8c4059b7c88c","origin":1661308185042176577,"deviceName":"Random-Integer-Device","resourceName":"Int64","profileName":"Random-Integer-Device","valueType":"Int64","value":"-1452698031510521559"}]},{"apiVersion":"v2","id":"34b0c74f-2a43-45e1-8eca-43b71f7d90d5","deviceName":"Random-Integer-Device","profileName":"Random-Integer-Device","sourceName":"Int8","origin":1661308200042300490,"readings":[{"id":"9af1135f-aff4-429e-9b39-b9c60d45395e","origin":1661308200042300490,"deviceName":"Random-Integer-Device","resourceName":"Int8","profileName":"Random-Integer-Device","valueType":"Int8","value":"75"}]},{"apiVersion":"v2","id":"6aa9ebdd-ce99-4912-a5e3-04f1e543908a","deviceName":"Random-Integer-Device","profileName":"Random-Integer-Device","sourceName":"Int64","origin":1661308200042908149,"readings":[{"id":"5b088c89-58a8-44c9-ae2a-2c9799e66c4c","origin":1661308200042908149,"deviceName":"Random-Integer-Device","resourceName":"Int64","profileName":"Random-Integer-Device","valueType":"Int64","value":"5100052631961015489"}]},{"apiVersion":"v2","id":"e7539c23-6030-4305-985c-4d6e2b5757ba","deviceName":"Random-Integer-Device","profileName":"Random-Integer-Device","sourceName":"Int64","origin":1661308215044071456,"readings":[{"id":"619f7cc4-24a5-437b-8b7b-3f59843d4289","origin":1661308215044071456,"deviceName":"Random-Integer-Device","resourceName":"Int64","profileName":"Random-Integer-Device","valueType":"Int64","value":"-6722451797880196521"}]},{"apiVersion":"v2","id":"1c5fdfbb-75fb-41af-a7b3-65ebd8644619","deviceName":"Random-Integer-Device","profileName":"Random-Integer-Device","sourceName":"Int8","origin":1661308215043459018,"readings":[{"id":"22f31e1a-555a-4df3-826d-3675816790a4","origin":1661308215043459018,"deviceName":"Random-Integer-Device","resourceName":"Int8","profileName":"Random-Integer-Device","valueType":"Int8","value":"-23"}]},{"apiVersion":"v2","id":"6c4597d4-321c-4666-ac1a-25a83f4ea29d","deviceName":"Random-Integer-Device","profileName":"Random-Integer-Device","sourceName":"Int8","origin":1661308230047833259,"readings":[{"id":"af07c7a1-a046-4fb3-a7d4-bb72a6c25434","origin":1661308230047833259,"deviceName":"Random-Integer-Device","resourceName":"Int8","profileName":"Random-Integer-Device","valueType":"Int8","value":"14"}]},{"apiVersion":"v2","id":"e2f8f8af-b3a3-4dec-89d8-b3ef975e943e","deviceName":"Random-Integer-Device","profileName":"Random-Integer-Device","sourceName":"Int64","origin":1661308230048081812,"readings":[{"id":"ab5b31de-9101-4261-a3e6-1814eb35ae6f","origin":1661308230048081812,"deviceName":"Random-Integer-Device","resourceName":"Int64","profileName":"Random-Integer-Device","valueType":"Int64","value":"6719054418441000012"}]}]
[Wed Aug 24 11:31:09 JST 2022]Receive Data : [{"apiVersion":"v2","id":"8616fa08-277b-4ee3-8ae4-a1c699f7ee66","deviceName":"Random-Integer-Device","profileName":"Random-Integer-Device","sourceName":"Int8","origin":1661308245049770325,"readings":[{"id":"05b5ff64-b7f8-427b-97e3-8bfeaa7b1831","origin":1661308245049770325,"deviceName":"Random-Integer-Device","resourceName":"Int8","profileName":"Random-Integer-Device","valueType":"Int8","value":"-69"}]},{"apiVersion":"v2","id":"3015250c-669e-4861-bbd9-f3952f096593","deviceName":"Random-Integer-Device","profileName":"Random-Integer-Device","sourceName":"Int64","origin":1661308245051216012,"readings":[{"id":"a506cad2-00dd-419d-9438-b6abe196bdc8","origin":1661308245051216012,"deviceName":"Random-Integer-Device","resourceName":"Int64","profileName":"Random-Integer-Device","valueType":"Int64","value":"-1057270830618329933"}]},{"apiVersion":"v2","id":"2420dadc-4585-4f8d-9d77-ea0b532871ec","deviceName":"Random-Integer-Device","profileName":"Random-Integer-Device","sourceName":"Int8","origin":1661308260051214556,"readings":[{"id":"f92830d8-b582-4b17-926c-4bb5028314e3","origin":1661308260051214556,"deviceName":"Random-Integer-Device","resourceName":"Int8","profileName":"Random-Integer-Device","valueType":"Int8","value":"20"}]},{"apiVersion":"v2","id":"88b921d0-b021-411a-903c-2745d12c854a","deviceName":"Random-Integer-Device","profileName":"Random-Integer-Device","sourceName":"Int64","origin":1661308260052073065,"readings":[{"id":"2859becb-d93d-45d1-95d6-1aa44c4c7e6e","origin":1661308260052073065,"deviceName":"Random-Integer-Device","resourceName":"Int64","profileName":"Random-Integer-Device","valueType":"Int64","value":"-691395134694160301"}]},{"apiVersion":"v2","id":"ec32cae6-13c9-49bb-8a53-ffdafa303c9b","deviceName":"Random-Integer-Device","profileName":"Random-Integer-Device","sourceName":"Int8","origin":1661308275052397107,"readings":[{"id":"1ba79a2c-9824-4cd0-b163-f87815c0301f","origin":1661308275052397107,"deviceName":"Random-Integer-Device","resourceName":"Int8","profileName":"Random-Integer-Device","valueType":"Int8","value":"-106"}]},{"apiVersion":"v2","id":"00cbbeaf-278e-42b8-b1a6-4c4f58331e01","deviceName":"Random-Integer-Device","profileName":"Random-Integer-Device","sourceName":"Int64","origin":1661308275052731084,"readings":[{"id":"372a57c7-0be4-4fe2-bef4-0ac3eed92674","origin":1661308275052731084,"deviceName":"Random-Integer-Device","resourceName":"Int64","profileName":"Random-Integer-Device","valueType":"Int64","value":"6605794569171066496"}]},{"apiVersion":"v2","id":"d6445249-514b-4a34-8fce-1ec609ce7a79","deviceName":"Random-Integer-Device","profileName":"Random-Integer-Device","sourceName":"Int64","origin":1661308290053673687,"readings":[{"id":"8952ca8d-667b-4e62-bef1-ba8f688a235b","origin":1661308290053673687,"deviceName":"Random-Integer-Device","resourceName":"Int64","profileName":"Random-Integer-Device","valueType":"Int64","value":"-8246083674465192471"}]},{"apiVersion":"v2","id":"f1700407-a8b6-488c-a318-5cd0679bde1b","deviceName":"Random-Integer-Device","profileName":"Random-Integer-Device","sourceName":"Int8","origin":1661308290053449523,"readings":[{"id":"cb343b69-aee7-4fef-b76c-5b76ebaa6214","origin":1661308290053449523,"deviceName":"Random-Integer-Device","resourceName":"Int8","profileName":"Random-Integer-Device","valueType":"Int8","value":"-22"}]}]

今回はローカルのPCを宛先にしていますが、AWSのApiGatewayのようなリクエスト回数でも課金されるサービスをサーバ側の受け手てとして使用する場合、batch機能でまとめて送信という形になるでしょう。
さらに「Compress」などを使用してデータ圧縮を行い、通信データ量も減らすこともできるので、サーバにデータを上げるのに必要な機能はapp-sampleのサービスで一通り体験できます。
データのカスタマイズ(一定時間の平均値、最大値、最小値を算出したデータにしたい場合など)に関しては「app-sample」をベースに改修して作れるでしょう。

体験しての感想

プラットフォーム自体がDockerで起動できることもありますが、「EdgeX UI」もあって、仮想デバイスからサーバへの送信はシンプルなものとはいえ、サーバ側のコーディングを除いては実装いらず体験できました。
実際にはデバイスが上げてきたデータの分析・加工やデバイスに沿ったサービスの実装も必要になりますが、それを試すための下準備環境としては十分に使用でき、開発の導入としては十分です。
これでAWSのクラウド上にApiGatewayとLambdaとDynamoDBなどを一式用意すれば、もうサーバまで上げるシステム全体環境が完成です。
ApiGatewayとLambdaとDynamoDBの組み合わせならば、データをExportする周期やデータ量を調整すれば、さほどお金も掛かりません。

さらにラズパイにredisのデータから情報を収集して画面表示するアプリを作れば、サーバ側にアクセスしなくても直近のデバイスデータが参照できます。

まだまだ、拡張して楽しめる要素が多そうなので今後も色々と触っていきたいと思います。
ただ、その前にAWSが提供するEdgeコンピューティングサービスも触ってみて、見比べてみたいところです。