拙网论坛

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 171|回复: 0

IIoT edge development – Using OPC UA protocols

[复制链接]

949

主题

1001

帖子

3736

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3736
发表于 2020-1-14 16:40:38 | 显示全部楼层 |阅读模式

https://www.embedded.com/iiot-edge-development-using-opc-ua-protocols/

IIoT edge development – Using OPC UA protocols February 11, 2019 Embedded Staff


Editor's Note: The Industrial Internet of Things (IIoT) promises to provide deep insight into industrial operations and enhance efficiency of connected machines and systems. Large-scale IIoT applications rely on layered architectures to collect data from a broad range of sensors, move data reliably and securely to the cloud, and perform analysis required to deliver that insight and efficiency. In Industrial Internet Application Development, the authors provide a detailed examination of the IIoT architecture and discuss approaches for meeting the broad requirements associated with these systems.
Adapted from Industrial Internet Application Development, by Alena Traukina, Jayant Thomas, Prashant Tyagi, Kishore Reddipalli.

Chapter 3. IIoT Edge Development (Continued)
By Alena Traukina, Jayant Thomas, Prashant Tyagi, Kishore Reddipalli
Industrial M2M protocols – OPC UA
In this section, we will try to build a simple IoT app for sending data from a sensor simulator module to a receiver device (a PC or a cloud), using a Raspberry Pi hub and the OPC UA protocol:

Data flow from a sensor simulator to a receiver device
The OPC UA protocol is similar to Modbus, but works with more data types, and has no serious limitations, while providing for security, compression, and low latency.

广告




The protocol was developed by the OPC Foundation as an industrial machine-to-machine communication protocol. OPC UA (Unified Architecture) is an improved version of the Open Platform Communications (OPC ) protocol, with one of the major changes being that the new protocol is available free of charge without any restrictions.
In the following table, you can find a more detailed description of the protocol to understand whether it is suitable for your needs:
KeyValue
Open sourceYes
The OSI layerTransport or application
Data typesInteger, float, string, Boolean, date, time, and so on
LimitationsNot suitable for a complex architecture
Possible operationsRead/write/monitor/query variables
LatencyLow
UsageIIoT
SecurityYes
CompressionYes
Table 5: OPC UA protocol specifications
For building the application, we will need the following:
  • Required software
    • Node.js 6+ (https:/​/​nodejs.​org/​en/​download/​)
    • PostgreSQL (https:/​/​www.​postgresql.​org/​download/​)
    • The 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/​)
  • Required hardware
    • Raspberry Pi 3 (model B)
    • A power adapter (2A/5V)
    • A microSD card (8 GB+) and an SD adapter
    • Ethernet cable for a wired network connection


Preparing an SD card
To prepare an SD card, follow the sequence of actions as described:
cd /Volumes/boot touch ssh
  • To enable Wi-Fi, create conf with the following content:

network={
   ssid=”YOUR_SSID”
   psk=”YOUR_WIFI_PASSWORD”
}
To create a file in a Linux console, you can use the GNU nano editor. It is pre-installed in most Linux distributives. All you need is to run the nano FILE_NAME command and follow the displayed instructions.
  • Create the /home/pi/hub
  • Create the /home/pi/hub/package.json file with the following content:

{
   “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”
   }
}
  • Create the /home/pi/hub/index.js file with the following content, replacing

REMOTE-SERVER-ADDRESS.com and REMOTE-SENSOR-ADDRESS with real values:
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 = “http://REMOTE-SERVER-ADDRESS.com:8080”;
async.series( [
// establishing connection function (cb) {
   client.connect(sensor, function (err) {
      if (err) {
         console.log(“Connection to ” + sensor + “failed”);
      } else {
         console.log(“Connection successful”);
      }
      cb(err);
   });
},
// start session function (cb) {
   client.createSession(function (err, res) {
      if (!err) session = res;
      cb(err);
   });
},
// read value
function (cb) {
   session.readVariableValue(“ns=1;s=Variable1”, function (err, dataValue) {
      if (!err) console.log(“Variable1 = “, dataValue.value.value);
      cb(err);
   });
},
// write value
function (cb) {
   session.writeSingleNode(“ns=1;s=Variable1”, new opcua.Variant({
      dataType: opcua.DataType.Double, value: 100
   }), function (err) {
      cb(err);
   });
},
// subscribe to changes
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);
   // install monitored item
   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);
      // send to receiver
      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);
   });
});
},
// close session
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 () {
});
}
);
  • Create the /home/pi/hub/Dockerfile file with the following content:

FROM hypriot/rpi-node:boron-onbuild
  • Create the /home/pi/sensor
  • Create the /home/pi/sensor/package.json file with the following content:

{
   “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”
   }
}
  • Create the /home/pi/sensor/index.js file with the following content:

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;
   // generate new value
   setInterval(function () {
      variable1 = Math.floor(max – Math.random() * (max – min));
   }, 500);
   space.addVariable({
      browseName: “browseName”,
      componentOf: componentOf,
      dataType: “Double”,
      nodeId: “ns=1;s=Variable1”, // a string 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);
   });
});
  • Configure the min and max values at the beginning of the

/home/pi/sensor/index.js file.
  • Create the /home/pi/sensor/Dockerfile file with the following content:

FROM hypriot/rpi-node:boron-onbuild
Running a simulator application on an RPi
To run a simulator on an RPi, proceed as the following steps suggest:
  • Insert an SD card into the
  • Connect an Ethernet cable and open an SSH connection.
  • Navigate to /home/pi/sensor.

  • Build an image and run a Docker container:

# Build an image from a Dockerfile
docker build -t opcua-sensor .
#
# Run container in foreground
docker run -p 4334:4334 –privileged -it –rm –name opcua-sensor- container opcua-sensor
#
# Run container in background
# docker run -p 4334:4334 –privileged -d  –rm –name opcua- sensor-container opcua-sensor
#
# Fetch the logs of a container
# docker logs -f opcua-sensor-container #
# Stop running container
# docker stop opcua-sensor-container

Console output when a simulator app is running
Running a receiver application on a PC
To run a receiver app on a PC, follow the sequence described here:
  • Install and launch a PostgreSQL container:

docker run –rm –name postgres-container -e POSTGRES_PASSWORD=password -it -p 5433:5432 postgres
docker exec -it postgres-container createdb -U postgres iot-book
  • Create the receiver

  • Create the ./receiver/package.json file with the following content:

{
   “name”: “receiver”,
   “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”: {
      “pg”: “^6.2.3”
   }
}
  • Create the ./receiver/index.js file with the following content, replacing the database credentials with the correct values:

var restify = require('restify');
var server = restify.createServer({name: 'MyApp'});
   server.use(restify.bodyParser());
   var Pool = require('pg').Pool;
   var pool = new Pool({
      database: 'iot-book',
      host: 'host',
      password: 'password',
      port: 5433,
      user: 'postgres',
   });
   //ensure table exists in db
   pool.query('CREATE TABLE IF NOT EXISTS “sensor-logs” (id serial NOT NULL PRIMARY KEY, data json NOT NULL)', function (err, result) {
      if (err) console.log(err);
   });
   server.post('/', function create(req, res, next) {
      console.log(req.params);
      //save in db
      pool.query('INSERT INTO “sensor-logs” (data) VALUES ($1)', [req.params], function (err, result) {
         if (err) console.log(err);
         res.send(201, result);
      });
      return next();
   });
   server.get('/stats', function search(req, res, next) {
      pool.query('SELECT AVG(“Variable1”), MAX(“Variable1”),
      MIN(“Variable1”), COUNT(*), SUM(“Variable1”) FROM (SELECT
      (data->>'Variable1')::int “Variable1” FROM “sensor-logs” ORDER BY id DESC LIMIT 10) data', function (err, result) {
         if (err) console.log(err); res.send(result.rows);
      });
      return next();
   });
   server.listen(process.env.PORT || 8080);
   
  • Create the ./receiver/Dockerfile file with the following content:

FROM node:boron-onbuild EXPOSE 8080
  • Build an image and run a Docker container:

# Build an image from a Dockerfile
docker build -t opcua-receiver .
# Run container in foreground
docker run -p 8080:8080 -it –rm –name opcua-receiver-container opcua-receiver
# Run container in background
# docker run -p 8080:8080 -d  –rm –name opcua-receiver-container opcua-receiver
# Fetch the logs of a container
# docker logs -f opcua-sensor-container
# Stop running container
# docker stop opcua-receiver-container

Console output when a receiver app is running
Running a receiver application in Predix
To run a receiver app in Predix, follow this sequence:
  • Install and connect the Сloud Foundry CLI to your Predix
  • Create a PostgreSQL service and obtain the

  • Create the ./receiver/manifest.yml file with the following content:

applications:

name: receiver
memory: 128M
random-route: true
  • Replace the database credentials in ./receiver/index.js.
  • Deploy to the cloud:

cf push
  • Change the REMOTE-SERVER-ADDRESS in the hub application on the RPi to the newly deployed

Running a hub application on an RPi
To run a hub application on an RPi, proceed as follows:
  • Open an SSH
  • Navigate to /home/pi/hub.
  • Build an image and run a Docker container:

# Build an image from a Dockerfile
docker build -t opcua-hub .
#
# Run container in foreground
docker run –privileged -it –rm –name opcua-hub-container opcua- hub
#
# Run container in background
# docker run –privileged -d  –rm –name opcua-hub-container opcua-hub
#
# Fetch the logs of a container
# docker logs -f opcua-hub-container
#
# Stop running container
# docker stop opcua-hub-container

Console output when a hub app is running
Getting statistics
To get statistics on sensor data, one needs to open a browser and navigate to
http://RECEIVER-ADDRESS:8080/stats or https://RECEIVER-IN-PREDIX/stats:
[
   {
      “avg”: “64.3”,
      “max”:100,
      “min”:17,
      “count”:”10″,
      “sum”:”643″
   }
]
Reprinted with permission from Packt Publishing. Copyright © 2018 Packt Publishing

About the authors
Alena Traukina is IoT practice Lead at Altoros. She has over 12 years of experience in delivery and support of business-critical software applications and is one of the first GE's Predix Influencers.
Jayant Thomas (JT) is the director of software engineering for the IoT apps for GE Digital. He is responsible for building IoT SaaS applications using the Predix platform, and specializes in building microservices-based architecture, reactive, event-driven systems.
Prashant Tyagi is responsible for enabling the big data strategy at GE Digital for the Industrial Internet that leverages IT and Operational data for predictive analytics. He works with all the P&L verticals (such as oil and gas, power generation, aviation, healthcare, and so on) to enable their IoT use cases on the data and analytics platform.
Kishore Reddipalli is a software technical director and expert in building IIoT big data and cloud computing platform and products at ultra scale. He is passionate in building software for analytics and machine learning to make it simplified for authoring the algorithms from inception to production at scale.




回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|抱朴守拙BBS

GMT+8, 2025-5-26 05:08 , Processed in 0.191017 second(s), 18 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表