OPC UAを活用した堅牢なIIoTエッジ開発
編集者注:産業用IoT(IIoT)は産業運用への深い洞察を提供し、接続された機械とシステムの効率を向上させることを約束します。大規模IIoTアプリケーションは階層型アーキテクチャに依存し、幅広いセンサーからデータを収集し、データを確実かつ安全にクラウドに移動し、その洞察と効率を提供するために必要な分析を実行します。『産業用インターネットアプリケーション開発』では、著者らがIIoTアーキテクチャを詳細に検証し、これらのシステムに関連する幅広い要件を満たすアプローチについて議論しています。
『産業用インターネットアプリケーション開発』より抜粋、Alena Traukina、Jayant Thomas、Prashant Tyagi、Kishore Reddipalli著。
第3章. IIoTエッジ開発(続き)
Alena Traukina、Jayant Thomas、Prashant Tyagi、Kishore Reddipalli著
産業用M2Mプロトコル — OPC UA
このセクションでは、Raspberry PiハブとOPC UAプロトコルを使用して、センサーシミュレーターモジュールから受信デバイス(PCまたはクラウド)へデータを送信するシンプルなIoTアプリの構築を試みます:

センサーシミュレーターから受信デバイスへのデータフロー
OPC UAプロトコルはModbusに似ていますが、より多くのデータタイプを扱い、深刻な制限がなく、セキュリティ、圧縮、低レイテンシを提供します。
このプロトコルはOPC Foundationによって産業用マシンツーマシン通信プロトコルとして開発されました。OPC UA(Unified Architecture)は、Open Platform Communications(OPC)プロトコルの改良版であり、主要な変更の一つは新しいプロトコルが制約なしで無料で利用可能になったことです。
以下の表で、プロトコルのより詳細な説明を見て、あなたのニーズに適しているかどうかを判断できます:
| キー | 値 |
|---|---|
| オープンソース | はい |
| OSI層 | トランスポートまたはアプリケーション |
| データタイプ | 整数、浮動小数点、文字列、ブール、日付、時刻など |
| 制限 | 複雑なアーキテクチャには不向き |
| 可能な操作 | 変数の読み書き/監視/クエリ |
| レイテンシ | 低い |
| 用途 | IIoT |
| セキュリティ | あり |
| 圧縮 | あり |
表5: OPC UAプロトコル仕様
アプリケーション構築には以下が必要です:
- 必要なソフトウェア
- Node.js 6+ (https://nodejs.org/en/download/)
- PostgreSQL (https://www.postgresql.org/download/)
- Cloud Foundry CLI (https://github.com/cloudfoundry/cli#downloads)
- Request (https://www.npmjs.com/package/request)
- NodeOPCUA (https://www.npmjs.com/package/node-opcua)
- Async (https://www.npmjs.com/package/async)
- Docker (https://docs.docker.com/engine/installation/)
- 必要なハードウェア
- Raspberry Pi 3(モデルB)
- 電源アダプター(2A/5V)
- microSDカード(8GB以上)とSDアダプター
- 有線ネットワーク接続用Ethernetケーブル
SDカードの準備
SDカードを準備するには、以下の手順に従ってください:
最新のRaspbian LITEイメージをダウンロード(https://raspberrypi.org/downloads/raspbian/ で入手可能)。
SDカードをコンピューターに接続し、Etcher(https://www.balena.io/etcher/)を使用してRaspbian .imgファイルをSDカードに書き込み。
SSHを有効化:
cd /Volumes/boot
touch ssh
Wi-Fiを有効化するには、以下の内容で
confを作成:
network={
ssid="YOUR_SSID"
psk="YOUR_WIFI_PASSWORD"
}
Linuxコンソールでファイルを作成するには、ほとんどのLinuxディストリビューションにプリインストールされているGNU nanoエディターを使用できます。nano ファイル名 コマンドを実行し、表示される指示に従うだけです。
/home/pi/hubを作成/home/pi/hub/package.jsonファイルを以下の内容で作成:
{
"name": "hub",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"async": "^2.4.0",
"node-opcua": "0.0.64",
"request": "^2.81.0"
}
}
/home/pi/hub/index.jsファイルを以下の内容で作成、REMOTE-SERVER-ADDRESS.comとREMOTE-SENSOR-ADDRESSを実際の値に置き換え:
var opcua = require("node-opcua"); var async = require("async");
var request = require("request");
var session, subscription;
var client = new opcua.OPCUAClient();
var sensor = "opc.tcp://REMOTE-SENSOR-ADDRESS:4334/UA/resourcePath";
var receiver = "https://REMOTE-SERVER-ADDRESS.com:8080";
async.series( [
// 接続確立
function (cb) {
client.connect(sensor, function (err) {
if (err) {
console.log("Connection to " + sensor + "failed");
} else {
console.log("Connection successful");
}
cb(err);
});
},
// セッション開始
function (cb) {
client.createSession(function (err, res) {
if (!err) session = res;
cb(err);
});
},
// 値読み取り
function (cb) {
session.readVariableValue("ns=1;s=Variable1", function (err, dataValue) {
if (!err) console.log("Variable1 = ", dataValue.value.value);
cb(err);
});
},
// 値書き込み
function (cb) {
session.writeSingleNode("ns=1;s=Variable1", new opcua.Variant({
dataType: opcua.DataType.Double, value: 100
}), function (err) {
cb(err);
});
},
// 変更購読
function (cb) {
subscription = new opcua.ClientSubscription(session, {
maxNotificationsPerPublish: 5,
priority: 5,
publishingEnabled: true,
requestedLifetimeCount: 5,
requestedMaxKeepAliveCount: 3,
requestedPublishingInterval: 500,
});
subscription.on("started", function () {
console.log("subscription id: ", subscription.subscriptionId);
}).on("terminated", function () {
cb();
});
setTimeout(function () {
subscription.terminate();
}, 5000);
// 監視アイテムインストール
var monitor = subscription.monitor({
attributeId: opcua.AttributeIds.Value,
nodeId: opcua.resolveNodeId("ns=1;s=Variable1"),
},
{
discardOldest: true,
samplingInterval: 50,
queueSize: 5,
},
opcua.read_service.TimestampsToReturn.Both
);
monitor.on("changed", function (dataValue) {
console.log("Variable1 = ", dataValue.value.value);
// 受信機に送信
var data = {
device: "sensor1",
timestamp: Date.now(),
Variable1: dataValue.value.value
};
request.post({url: receiver, form: data}, function (err) {
if (err) console.log("Failed to send " + JSON.stringify(data) + " to " + receiver);
});
});
},
// セッションクローズ
function (cb) {
session.close(function (err) {
if (err) console.log("Failed to close session"); cb();
});
},
],
function (err) { if (err) {
console.log("Failed with error:", err);
} else {
console.log("Successfully finished");
}
client.disconnect(function () {
});
}
);
/home/pi/hub/Dockerfileファイルを以下の内容で作成:
FROM hypriot/rpi-node:boron-onbuild
/home/pi/sensorを作成/home/pi/sensor/package.jsonファイルを以下の内容で作成:
{
"name": "sensor",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"node-opcua": "0.0.64"
}
}
/home/pi/sensor/index.jsファイルを以下の内容で作成:
var opcua = require("node-opcua");
var min = 1;
var max = 100;
var host = new opcua.OPCUAServer({ buildInfo: {
buildDate: new Date(2018, 8, 8),
buildNumber: "1234",
productName: "productName",
},
port: 4334,
resourcePath: "UA/resourcePath",
});
host.initialize(function () {
var space = host.engine.addressSpace;
var componentOf = space.addObject({
browseName: "browseName",
organizedBy: space.rootFolder.objects,
});
var variable1 = 0;
// 新しい値を生成
setInterval(function () {
variable1 = Math.floor(max - Math.random() * (max - min));
}, 500);
space.addVariable({
browseName: "browseName",
componentOf: componentOf,
dataType: "Double",
nodeId: "ns=1;s=Variable1", // 文字列nodeID
value: {
get: function () {
return new opcua.Variant({dataType: opcua.DataType.Double, value: variable1});
},
set: function (variant) {
variable1 = parseFloat(variant.value);
return opcua.StatusCodes.Good;
}
}
});
host.start(function () {
var endpoint = host.endpoints[0].endpointDescriptions()[0].endpointUrl; console.log("Endpoint: ", endpoint);
});
});
/home/pi/sensor/index.jsファイルの冒頭でminとmaxの値を設定
/home/pi/sensor/Dockerfileファイルを以下の内容で作成:
FROM hypriot/rpi-node:boron-onbuild
モノのインターネットテクノロジー
- Glassboard: 3Dプリントで迅速・確実な製品開発を実現
- ECM3532:Eta Compute初の統合超低消費電力AIセンサーボード、エッジ開発を加速
- 産業用IoTセキュリティ:2020年の主要トレンドとベストプラクティス
- シスコ、包括的IIoTセキュリティアーキテクチャとエッジインテリジェンスを発表しOT可視化を実現
- 産業用 IoT のセキュア化:戦略、標準、信頼の連鎖
- 将来展望:生産卓越性に向けた産業用IoTの推進
- エッジコンピューティング:リアルタイム産業IoT成功の鍵
- IIoTとAIでメーカー/ディストリビューターの売上と生産性を向上
- コンテナがアジャイルIoTアプリ開発を強化
- エッジ・コンピューティングとIIoT:産業データ戦略の変革
- 次世代ツールが5Gとエッジ・コンピューティングの採用を加速