Category Archives: WinCC OA

Unity3D in WinCC Open Architecture

This article is about integrating your 3D Unity applications into WinCC Open Architecture SCADA HMI Web screens and exchanging property values. It only works with the WinCC Ultralight Web Client. Because the native Ui does not support WebGL in the WebView Widget. Update: It should also work in the native Ui, you just have to set the environment variable: QTWEBENGINE_CHROMIUM_FLAGS=–enable-gpu

With this free Unity Asset you can create a Unity application with an interface to the SCADA system in an easy way. Don’t be confused about the name of the Asset “WinCC Unified Custom Web Control”. This is because initially it was build to create Custom Web Controls for WinCC Unified only. But there is now also an option to create a build of your Unity application for WinCC Open Architecture.

First create and build your Unity Application as described in the documentation of the Asset. You may also watch this video.

Just at the end execute the menu item to create a WinCC Open Architecture application, instead of WinCC Unified.

Create and load the WebView

Then copy the ZIP file to your WinCC OA project into the folder “data\html” and unzip the ZIP (for example C:\WinCC_OA_Proj\Test\data\html\UnityCustomControl).

In this tutorial our application is named “UnityCustomControl”. You have to replace this with the name of your Unity application.

Then you must insert a WebView into your screen.

And then you must load the generated Unity application in the Initialize script of the widget.

main()
{
   this.loadSnippet("/data/html/UnityCustomControl/index.html");
}

In the Property Editor at the Extended tab be sure to set the “ulcClientSideWidget” to TRUE.

Set and receive property values

To send values from your WinCC Open Architecture to the Unity application you must use execJsFunction of the Webview and call the “setPropertyInUnity” function with the property and the value which you want to set. See the following example.

UnityCustomControl.execJsFunction("setPropertyInUnity", "target_shoulder_link", 10);

“UnityCustomControl” is the name of our Webview Widget! It’s up to you how you name it.

At the WebView there is an event “messageReceived”. There you will get all the messages which are sent from Unity to WinCC Open Architecture. See the example for the structure of the parameter. It is always a JSON document which contains the Name and the Value of the property which has been sent.

Receiving Property Values:
WCCOAui2:["messageReceived"][mapping 3 items
WCCOAui2:   "uuid" : 2
WCCOAui2:   "command" : "msgToCtrl"
WCCOAui2:   "params" : mapping 2 items
WCCOAui2:	   "Name" : "test_property"
WCCOAui2:	   "Value" : "Hello World 1"
WCCOAui2:]

The very first message does not have any “params”, this message comes when the initialization of Unity is done.

First Message:
WCCOAui2:["messageReceived"][mapping 2 items
WCCOAui2:   "uuid" : 1
WCCOAui2:   "command" : "msgToCtrl"
WCCOAui2:]

Start Ultralight Web Client

Start a Control Manager with the “webclient_http.ctl” script.

Then you can open the application in the browser with “https://localhost/data/ulc/start.html”.

Generate QR Code Image in WinCC OA …

Add a label object into your screen and add some lines of code to get a QR image. In this example a mobile phone app will scan the QR code and send username and password via a GraphQL server to WinCC OA and set it on datapoints (username and password should additionally be encrypted).

#uses "CtrlQRCode"

string g_code;

main()
{
  g_code = createUuid();
  strreplace(g_code,"{", "");
  strreplace(g_code,"}", "");
  DebugTN(g_code);

  string fpath = PROJ_PATH+"/pictures/";
  string fname = "login_qr_code_"+myUiNumber();
  int ret = createQRCodeFile(g_code, fpath+fname);
  this.image=fname+".png";

  dpConnect("work", false, "QRLogin.code", "QRLogin.usr", "QRLogin.pwd");
}

void work(string dp, string code, string dp1, string usr, string dp2, string pwd)
{
  if (code == g_code)
  {
    setInputFocus(myModuleName(), myPanelName(), txt_username.name());
    txt_username.text = usr;
    setInputFocus(myModuleName(), myPanelName(), txt_password.name());
    txt_password.text = pwd;
    m_loginFrameworkController.doContinue();
  }
}

WinCC OA on Docker, Dockerfiles and Howto’s…

This repository on Github contains Dockerfiles and samples to build Docker images for WinCC OA products.

Build Docker Image

Download and unzip the CentOS WinCC OA rpm’s to the centos/software directory.

Only put those WinCC OA rpm’s into the directory which you want to have installed in your image. For a minimum image you only need the base packag of WinCC OA.

WinCC_OA_3.16-base-rhel-0-17.x86_64.rpm

Build your WinCC OA Docker image with:

docker build -t winccoa:3.16 .

WinCC OA Project in a Container

The project should be mounted on /proj/start as a volume to your docker container.

And you may also mount a shield file to your docker container.

Example how to startup a WinCC OA project in a container:

docker run -d  
  --name winccoa  
  --hostname winccoa-server  
  -v ~/shield.txt:/opt/WinCC_OA/3.16/shield.txt  
  -v /proj/DemoApplication_3.16:/proj/start  
  -p 5678:5678  
  winccoa:3.16 

WinCC OA Gedi in a Container

To start a WinCC OA client application like a Gedi or a User-Interface you have to adapt your config file so that the proxy settings point to the WinCC OA server container. You can just create a copy of your config file (e.g. config.ui) and adapt the settings.

[general] 
data = "winccoa-server" 
event = "winccoa-server" 
mxProxy = "winccoa-server <your-docker-host-name>:5678 cert" 

Then you can startup a Gedi/Ui with:

docker run --rm  
-e DISPLAY=$DISPLAY  
-v /tmp/.X11-unix:/tmp/.X11-unix  
-v /proj/DemoApplication_3.16:/proj/default  
-v /proj/DemoApplication_3.16/config/config.ui:/proj/default/config/config  
winccoa:3.16  
WCCOAui -autoreg -m gedi -proj default 

Sure you can also use a copy of your project directory (or a git checkout if you use git) and adapt the config file.

Start Project Administration as Container

With the Project Administration you can create a new project in the /proj directory.

docker run -ti --rm 
-e DISPLAY=$DISPLAY 
-v /tmp/.X11-unix:/tmp/.X11-unix 
-v /proj:/proj 
winccoa:3.16 
WCCOAui -projAdmin

Distributed Managers and Kubernetes

For sure what we have done with the Gedi can also be done with Control-Managers and Drivers. And in theory that can also be done with Kubernetes and so you can run your SCADA project in a Kubernetes Cluster.

Use GraphQL in WinCC OA …

This is a simple example how to query a GraphQL server from WinCC OA ctrl via HTTP.

{
  string url = "https://server.rocworks.at/graphql";

  string query = "query($tag: String!){getTag(name: $tag){tag{current{value}}}}";

  mapping variables = makeMapping("tag", "Input");

  mapping content = makeMapping("query", query, "variables", variables);

  mapping data = makeMapping(
      "headers", makeMapping("Content-Type", "application/json"),
      "content", jsonEncode(content)
  );

  mapping result;

  netPost(url, data, result);

  if (result["httpStatusText"]=="OK") {
    DebugTN(result["content"]);
  }
  else {
    return "Error";
  }
}

Output:

{
   "data": {
     "getTag": {
       "tag": {
         "current": {
           "value": 280.87696028711866
         }
       }
     }
   }
 }

WinCC OA OPC UA Server

For testing sometimes it is too hard to deal with security :-). To make the OPC UA server in WinCC OA unsecure add the following lines to the config file.

[opcuasrv]
disableSecurity = 1
enableAnonymous = 1

Add the WCCOAopcuasrv manager to the project and start it.

To publish datapoints don’t forget to add the datapoints to the DP groups “OPCUARead” and “OPCUAWrite”.

Python and WinCC OA…

Connected Python to WinCC OA through a Websocket Manager. Python programs can connect to WinCC OA and read/write datapoints. Communication is JSON based, it’s simple to use in Python, see examples below (ws://rocworks.no-ip.org can be used for tests, but will not be available all the time).

https://github.com/vogler75/oa4j-wss

  1. dpGet
  2. dpSet
  3. dpConnect
  4. dpQueryConnect
  5. dpGetPeriod
  6. … more functions will be implemented

Required Python modules:

  • pip3 install websocket-client
  • pip3 install matplotlib

############################################################
# Open Connection
############################################################
import json
import ssl
from websocket import create_connection
url='ws://rocworks.no-ip.org/winccoa?username=demo&password=demo'
ws = create_connection(url, sslopt={"cert_reqs": ssl.CERT_NONE})

############################################################
# dpGetPeriod
############################################################
cmd={'DpGetPeriod': {
 'Dps':['ExampleDP_Trend1.'],
 'T1': '2018-02-07T18:10:00.000', 
 'T2': '2018-02-07T23:59:59.999',
 'Count': 0, # Optional (Default=0)
 'Ts': 0 # Optional (0...no ts in result, 1...ts as ms since epoch, 2...ts as ISO8601)
 }}
ws.send(json.dumps(cmd))
res=json.loads(ws.recv())
#print(res)
if "System1:ExampleDP_Trend1.:_offline.._value" in res["DpGetPeriodResult"]["Values"]:
 values=res["DpGetPeriodResult"]["Values"]["System1:ExampleDP_Trend1.:_offline.._value"]
 print(values)
else:
 print("no data found")

# Plot result of dpGetPeriod
%matplotlib inline 
import matplotlib.pyplot as plt
plt.plot(values)
plt.ylabel('ExampleDP_Trend1.')
plt.show()

############################################################
# dpGet
############################################################
cmd={'DpGet': {'Dps':['ExampleDP_Trend1.', 'ExampleDP_Trend2.']}}
ws.send(json.dumps(cmd))
res=json.loads(ws.recv())
print(json.dumps(res, indent=4, sort_keys=True))

############################################################
# dpSet
############################################################
from random import randint
cmd={'DpSet': {'Wait': True, 
 'Values':[{'Dp':'ExampleDP_Trend1.','Value': randint(0, 9)}, 
 {'Dp':'ExampleDP_Trend2.','Value': randint(0, 9)}]}}
ws.send(json.dumps(cmd))
res=json.loads(ws.recv())
print(json.dumps(res, indent=4, sort_keys=True))

############################################################
# dpConnect
############################################################
from threading import Thread

def read():
    while True:
        res=json.loads(ws.recv())
        print(res)
Thread(target=read).start()
    
cmd={"DpConnect": {"Id": 1, "Dps": ["ExampleDP_Trend1."]}}
ws.send(json.dumps(cmd))



Streaming SQL for Apache Kafka & WinCC OA with Docker…

KSQL makes it easy to read, write, and process streaming data in real-time, at scale, using SQL-like semantics. It offers an easy way to express stream processing transformations as an alternative to writing an application in a programming language such as Java or Python. https://www.confluent.io/product/ksql/

With WinCC OA Java (https://github.com/vogler75/oa4j) we can stream data from WinCC OA to Apache Kafka, use KSQL to produce some insights and send it back to WinCC OA by using a WinCC OA Driver written in Java connected to Kafka.

Attached you will find a docker-compose.yml to setup KSQL + WinCC OA Connector and Driver to test it. Just use “docker-compose up -d” to start up everything. Before you should set the “data” and “event” environment variables in the docker-compose.yml to point to a running WinCC OA project.

root@docker1:~/docker/builds/winccoa# docker-compose up -d

Creating winccoa_frontend_1 ==> collect data from OA and publish it by ZeroMQ

Creating winccoa_backend-kafka_1 ==> get the data from the Frontend and write it to Kafka

Creating winccoa_driver-kafka_1 ==> OA driver to read data from kafka.

Creating winccoa_zookeeper_1
Creating winccoa_kafka_1
Creating winccoa_schema-registry_1
Creating winccoa_ksql-cli_1

We use Docker to startup WinCCOA Mangers (frontend, backend) and Drivers.

Afterwards you can start KSQL: docker-compose exec ksql-cli ksql-cli local –bootstrap-server kafka:29092

Create a stream of the topic which is sent from WinCC OA to kafka (currently every change of value in WinCC OA is sent to Kafka):

CREATE STREAM Scada_FloatVar (TimeMS BIGINT, Status BIGINT, Value DOUBLE) WITH (kafka_topic=’Scada_FloatVar’, value_format=’JSON’);

Create a result table in KSQL which will be read by the WinCC OA Driver, here we detect if a datapoint changes more often than 5 times in 10 seconds. Just a simple example to show how KSQL can be used:

CREATE TABLE result WITH (PARTITIONS=1) AS SELECT rowkey AS “Name”, count(*) AS “Value” FROM Scada_FloatVar WINDOW TUMBLING (size 10 second) GROUP BY rowkey HAVING count(*) > 5;

In WinCC OA you should put a peripheral address on a datapoint with the example driver (num 4) to get the result back (you will need the panels and scripts from here https://github.com/vogler75/oa4j/tree/master/Project/Drivers/Kafka to use the driver).

docker-compose.yml