Git Product home page Git Product logo

freeopcua's Introduction

Open Source C++ OPC-UA Server and Client Library

Build Status

LGPL OPC-UA server and client library written in C++ and with a lot of code auto-generated from xml specification using python.

Python bindings can be found in the python directory.

code: https://github.com/FreeOpcUa/freeopcua
website: http://freeopcua.github.io/
mailing list: https://groups.google.com/forum/#!forum/freeopcua

Currently supported:

  • read, write, browse
  • translateBrowsePathToNodeId
  • DataChange Events
  • Events
  • Subscriptions
  • complete opc-ua address space generated from xml specification
  • Method call from client
  • Linux and Windows(VS13) support

Work in progress

  • StatusChange Events
  • Filtering
  • Documentation
  • Automatic generation of binary protocol from OPC schema files
    • Methods on server side

Not implemented yet (patches are welcome)

  • History
  • Security: Authentication, Certificates handling, ..

Usage

Documentation is sparse but several examples are availables:

C++ examples in https://github.com/FreeOpcUa/freeopcua/tree/master/src/examples
Python examples in https://github.com/FreeOpcUa/freeopcua/tree/master/python/src
https://github.com/FreeOpcUa/freeopcua/blob/master/python/tests/test_highlevel.py can also be a usefull source of information

Example minimal client in python

  client = opcua.Client(False)
  client.connect("opc.tcp://10.10.10.4:4841/OPCUA/AnyServer/")

  objects = client.get_objects_node()
  print("Children of objects are: ", objects.get_children())

  var = objects.get_child(["3:AnObject", "AVariable"])
  print("Value of variable is: ", var.get_value())
  
  client.disconnect()

Tested clients and servers with default settings

  • uaexperts client application
  • node-opcua (client and server tested)
  • ignition server
  • Beckhoff PLC (seems to be some issues, but mostly working)
  • ignition open-source sdk (server tested)
  • quickopc client sdk
  • prosysopc demo client
  • prosysopc demo server
  • unified automation sdk (client and server tested)

Installation

An environment supporting c++11 is necessary: gcc-4.8+, clang 3.4 or VS2013

Ubuntu (Debians)

There is a script debian.soft in the root for installing all required soft to build all repositories.

Using GNU autotools

autoreconf -f -i
./configure --prefix=/path/to/server
make 
make check
make install
cd /path/to/server
LD_LIBRARY_PATH=./lib ./bin/opcuaserver

Using cmake

Linux

mkdir build
cd build
cmake ..
make
make test

Windows

Boost and libxml2 are necessary

rem compiling
mkdir build
cd build
cmake .. -DBOOST_ROOT=c:\boost_1_56
cmake --build
ctest -C Debug
cd bin\Debug
example_server.exe

Docker

docker build .

Developement

C++ style

  • 2 spaces not tab
  • CamelCase
  • Local variables start with small letter
  • Global/member variables starts with capital letters
  • Use provided automatic formatter (Artistic Style) by invoking ./restyle

python code and API should follows PEP8 (many places should be fixed)

Address space and most protocol code are auto-generated and should not be modified directly. Every auto-generated file starts with a mention that it should not be edited. There's a lot of old hand written protocol code left that should use the auto-generated code. This is done by uncommenting struct names in schemas/generate_protocol.py and removing old code and files in src/protocol and include/opc/ua/protocol/

freeopcua's People

Contributors

a-sevin avatar arykovanov avatar ashubhatt avatar basyskom-swid avatar bkuner avatar bryant1410 avatar destogl avatar fvacek avatar informatikr avatar jokymon avatar kneisi avatar mdcb avatar morxa avatar oroulet avatar penguineer avatar phoenixdecim avatar pspeybro avatar qsodev avatar ralf1070 avatar ralphlange avatar raviln avatar reunanen avatar sam071100 avatar simhof-basyskom avatar smarsching avatar tbeu avatar tomkcook avatar tomneedham avatar vmatare avatar yayj avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

freeopcua's Issues

Wrong types in Python

Following the discussion in mailing list (Thread: "Setting correct types in OPC-UA server") I made a bit research through Python binding code and concluded the following.

The proposal to create new nodes with correct type using DataValue and than getting the value from it fails because while getting the value property it would be converted to Python object (e.g. int for all integer types in OpcUa (int16, uint16, int32...)). This happens in the line 198 of file py_opcua_module.cpp. This is probably what @oroulet tried to tell me but I didn't understand it.

Than I tried to enable Python access to Variant object uncommenting lines 421-428 in the py_opcua_module.cpp file. Also I added following line to enable setting a Variant type in the constructor:

//--------------------------------------------------------------------------
// Variant helpers
//--------------------------------------------------------------------------

static boost::shared_ptr<Variant> Variant_constructor1(const object & obj, VariantType vtype)
{return boost::shared_ptr<Variant>(ToVariant2(obj, vtype));}

and also

.def("__init__", make_constructor(Variant_constructor1)) //object, VariantType

into line 422.

I took the same approach as it is made for DataValue object. But than I got following runtime warning: RuntimeWarning: to-Python converter for OpcUa::Variant already registered; second conversion method ignored.
This is probably because the "opc/ua/protocol/variant_visitor.h" file is included from py_opcua_variant.h file therefore also "opc/ua/protocol/variant.h".

Ok, all this was to understand a problem and what I tried to do. Now something about possible solutions.

IMO the best approach would be to model Variant object in python bindings, maybe it has to be called different (e.g. VariantPy) so it would enable also work with variants in Python.

Second option is work with DataValue objects and creating following additional functions into bindings and, probably, c++ code:

.def("add_variable", (Node(Node::*)(const NodeID &, const QualifiedName &, const DataValue &) const) &Node::AddVariable)
.def("add_property", (Node(Node::*)(const NodeID &, const QualifiedName &, const DataValue &) const) &Node::AddProperty)

What solution would make more sense to you? Which approach would be more according to the library?

Thanks!

FLOAT byte ordering

Using the freeopcua client (python binding) against Beckhoff PLC to read a FLOAT variable gives:

  • plc: 12.34
  • client: -5.21003646196e-17

a trace on wireshark indicates the value is properly sent as float/12.34
adding some debug to opcua, it looks like a byte ordering issue:

12.34 = A4 70 45 41

-5.21003646196e-17 = 41 45 70 A4

The issue happens in both read and write direction.

Support structure in variant

I need this. and it does not seem to work. If a server sends variant containing structure, parsing fails.
Any idea how to implement this ?
It looks like structures are sent as bytestring type from server. simply a list of field values. I do not know how a client is supposed to know the order and type of fields .....

Bug: Writing empty string to the OPC UA server results in Null object with length -1

Hello,

last week during some test we found out that empty string (length 0) is written as Null object with length -1 into the server. The server on itself didn't have any problems with that some other clients like pyUAF was crashing when try to read variable. Currently I found workaround but it would be good to handle this on serializer level.

The workaround:

'''
if (variant.Type() == OpcUa::VariantType::STRING) {
if (((std::string)variant).length() == 0) {
variant = std::string(" ");
}
}
'''

Respect sessiontimeout and periodically send read request

We request no timeout, but CreateSessionResponse comes with a revisedTimeout parameter that we completely ignore. We should read ut and start a timer to reade periodically a node on server as uaexpert does.
Alexander, should we use the callbackThread for that? it is probably better to rename it than adding one more thread...
I can have a look at this issue

Subscription issues: namespace index from client not respected in server

Subscriptions from the Prosys sample client to the value of a freeopcua server variable do no work.
It appears that the wrong namespace index is being used (0).

Error message from freeopcua server:

SubscriptionService | Error request for publish queue for unknown session ns=0;i=9; 

(Missing space added before ns above)

It was not possible to test explicitly using 0 as a namespace index on either the server or client, due to errors received on both ends.
(I hard-coded 2 as the namespace index in the client, since the URI was not in the namespace array and I didn't know how to get it in there).

To reproduce, run a freeopcua server that defines a variable.
Then run the interactive Prosys sample client, navigate to the variable and subscribe to changes in the value. The server then gives the error. If you start a second client and write to the variable, no log message is displayed in the subscribed client as would be expected.

set_value fails when datetime is set

after pulling latest git head 2f3b75c
I get set_value failing with "opcua.StatusCode.BadWriteNotSupported"

digging around, and applying

diff --git a/src/core/node.cpp b/src/core/node.cpp
index 86cb377..dba626a 100644
--- a/src/core/node.cpp
+++ b/src/core/node.cpp
@@ -87,7 +87,7 @@ namespace OpcUa
     attribute.Node = Id;
     attribute.Attribute = attr;
     DataValue dval(value);
-    dval.SetSourceTimestamp(CurrentDateTime());
+//    dval.SetSourceTimestamp(CurrentDateTime());
     attribute.Data = dval;
     std::vector<StatusCode> codes = Server->Attributes()->Write(std::vector<WriteValue>(1, attribute));
     return codes.front();

set_value works again with "opcua.StatusCode.Good"

wireshark dump for both cases in attachment

set_value_without_datetime_good pcapng gz
set_value_with_datetime_bad pcapng gz

(remove the png extension used to fool github)

never crash when parsing client messages

When working on client I often got server crashes, this is quite bad, the server should never crash on bad or even malignent clients.
In one way or another we should have all parsing happen under try catch, and clearly report what message could not be parsed and maybe what was the last correct message parsed.

unable to connect from ignition

wireshark capture from connection attempts by Ignition OPC server by inductive automation can be found here: https://groups.google.com/forum/#!topic/freeopcua/vQ0ZCvmiBj0

Does the server have a discovery endpoint?
Ignition first does a "GetEndpoints" request at the dicovery endpoint to find out the available session endpoint urls.
Ignition assumes the dicovery endpoint is at host:port and expects that the getendpoints request returns a list with session endpoints (including security info like anonymous and so on)
Like explained here: http://j2eeps.cern.ch/wikis/plugins/viewsource/viewpagesrc.action?pageId=16023894

I tried to do a discovery request with some demo code from unified automation .Net client library but that didn't seem to work, so I guess that is the issue or one of the issues. (http://documentation.unified-automation.com/uasdkdotnet/2.2.2/html/L3ClientTutExample2.html )

beckhoff PLC: TranslateBrowsePathsToNodeIds fails

running some variation of the sample client (against beckhoff opc-ua server)

          std::vector<std::string> path({"Objects", "Server"});
          server = root.GetChild(path);

mostly fails, although on rare occasion, succeed.
more an annoyance than an a showstopper as I can access nodes by nodeId (low pri.)

attached compressed pcag with png ext. to full github

getchild_bad pcapng gz
getchild_good pcapng gz

Easy: Port as many structs as possible to auto-generated code

from older epost:
This push request enabled auto-generation #129 (alreadt merged)

auto-generated files end with _auto

Per default most of
the auto-generated code is commented out. As an example I removed all
code in attribute.h and replaced it with auto-generated code. But this
should be done for all simple structures and custom enum. but NOT for
more complicated stuff like NodeAttributes.

We also have a lot of custom enums that should be removed and use
ObjectId or autogenerated enums.

If someone is interrested take a look at schemas/generate_protocol,py
and try to uncomment the structs you are interested in. then run
generate_protocol .py. You will then need to remove hand written code.
The python code is written very quickly from the parser I made for
python but the generated c++ code should be OK

The autogeneated structs are sometimes different from those
handwritten. Then you need to do some small renaming but it should be easy

Bugs in OPC-UA xml spec

just a place holder for things that do not make sense in xml file from spec. Feel fri to comment and point to more errors or correct on things that are in fact correct.

  • Many struct are marked as inheriting ExtensionObject while they are not in pdf spec. for example "RequestHeader", "ResponseHeader", "ChannelSecurityToken", "UserTokenPolicy", "SignatureData", "BrowseResult", "ReadValueId"
  • All Request and Response are also defined as inheriting ExtensionObject while they are not, they just have a TypeId field
  • ExtensionObject definition is plain wrong in xml, the pdf defines them correctly (TypeId først, encoding second)
  • Bits definition in DataValue is wrong
  • Data type of namespace index in QualifiedName is of wrong type in xml

subscription fails with "Not enough data was received from channel."

running the subscription example, updates fails (but not systematically) with "Not enough data was received from channel."

  • The failure seems to be more systematic if I issue a set_value from the same client running the subscription.
  • but also occurs using a separate client (in this case, UAExpert running on a different host)

attached trace is a single session where 1 update came out Ok, second update came out with "not enough data". The update was triggered from UAExpert on other host, sample client was just running the subscription otherwise idle.

subscribe_1good_1bad pcapng gz

compressed pcap with .png to fool github

Client authentication

Quick question: Does the FreeOpcUa library support client authentication (with username/password)?

If not, is there any chance you could give a quick pointer to how it might be implemented?

Use a logging framework

We badly need a logging framework to clean up and give logging control to the users.
I see that boost just integrated a logging framework in 1_54. Can we use it?

simple example here:
http://torjo.com/log2/doc/html/scenarios_code.html#scenarios_code_mom

But I am missing the possibility to have a logger per call or module,,
log4j and the default c#/python logger all have methods that automatically format the output using the class name, I could not find the functionnality in boost logging .....

Unable to browse with UaExpert when subscribing for model change events

UaExpert reports a problem when connecting which results in being unable to browse the address space:
Register for ModelChangeEvents failed: createMonitoredItems returned BadDisconnect
Browse Failed with error 'BadConnectionClosed'

Setting UaExport option Global.SubscribeForModelChangeEvents to false avoids the issue allowing to browse.

fix occasional coredump at shutdown introduced with addressspace threading

Since I added a thread in addressspace for subscriptions we sometime get coredumps, especially at shutdown. We should find out why and fix it.
The reason is probaby callback to dead objects from the thread. But how can we avoid this?? Alexander, you wrote something about using weak pointers...

Implement server object node. class and addon.

I think it is required an object that will implement server object.
This object have to propagate:

  1. Build info and other static information.
  2. Current server time.

When time will be changed then automatically will appear ability to use subscriptions in practice. And that can used in be tests.

Client cannot connect to PLC

Hello all

I am trying to connect to a Beckhoff CX1000 PLC with Python FreeOpcUa client. The PLC device is running an OPC UA server.

I changed the OPC UA server endpoint address in the example Python program "client.py" and used it to connect to the PLC.

However, upon running the program with 'python client.py' I get this error message:

Traceback (most recent call last):
  File "client.py", line 28, in <module>
    client.connect("opc.tcp://192.84.180.76:4840")
RuntimeError: Unable to to resolve host 'CX_00D126'. Resource temporarily unavailable.

UaExpert (and also an older version of FreeOpcUa) can still connect to the PLC without problem.
Python version: 2.7.6

Client crashes when connected and disconnected more than 2 times in the row

Problem is that StopRequest is not set bac to false when KeepAlive thread is started again. Patch attached.

diff --git a/src/client/client.cpp b/src/client/client.cpp
index 399c31b..ab355c9 100644
--- a/src/client/client.cpp
+++ b/src/client/client.cpp
@@ -35,6 +35,7 @@ namespace OpcUa
     NodeToRead = node;
     Period = period;
     Running = true;
+    StopRequest = false;
     Thread = std::thread([this] { this->Run(); });
   }

@@ -44,8 +45,8 @@ namespace OpcUa
     if (Debug)  { std::cout << "KeepAliveThread | Starting." << std::endl; }
     while ( ! StopRequest )
     {
-      std::unique_lock<std::mutex> lock(Mutex);
       if (Debug)  { std::cout << "KeepAliveThread | Sleeping for: " << (int64_t) ( Period * 0.7 )<< std::endl; }
+      std::unique_lock<std::mutex> lock(Mutex);
       std::cv_status status = Condition.wait_for(lock, std::chrono::milliseconds( (int64_t) ( Period * 0.7) )); 
       if (status == std::cv_status::no_timeout ) 
       {

Problem closing the connection to OPC UA server

Hello,

I am a newbie programmer making a Python program with FreeOpcUa. I would like to periodically read the values of some variables from a PLC device.

I have set up a data_log() function which reads the values of some data variables from a UA server one by one and stores them to a database or text file. I would like to call this function periodically. However, when the data_log() function is finished executing and is closing the connection, the program exits with an exit status 134. At the end of the function execution I get this message:

CloseSession response is 
terminate called without an active exception
Aborted

------------------
(program exited with code: 134)
Press return to continue

The example client in "python/examples/" does not have this problem. The example client always exits cleanly with exit status 0. I would appreciate some advice on how to avoid this problem.

Full console output: http://pastebin.com/u3wNeV28
Main program file: http://pastebin.com/f5RRz6rW

async client

Client must ne ported to asio
-- to make subscription client work,
-- be portable to windows
-- to not hang if responses do not arrive in expected order

Easier: AddObject, AddVariable, AddProperty and AddFolder

Is there any particular reason why there is no function with the following prototype:

Node Node::AddFolder(const std::string& name) const

Where name is the name of the new node. Why is the namespaceId parameter, doesn't the parent Node doesn't know in which namespaceId it is?

various issues using the client API with Beckhoff OPC-UA server

I'm running the simple src/client demo against a bh server.

  • the part that does
          std::vector<std::string> path({"Objects", "Server"});
          server = root.GetChild(path);

is unreliable, it fails maybe 10 out of 1 times. sample output:

◾ ./a.out 
Connecting to: opc.tcp://10.10.1.16:4840
Root node is: Node(QualifiedName(0:Root), ns=0;i=84;)
No match for request
Root node is: Node(QualifiedName(0:Root), ns=0;i=84;)
No match for request
◾ ./a.out 
Connecting to: opc.tcp://10.10.1.16:4840
Root node is: Node(QualifiedName(0:Root), ns=0;i=84;)
No match for request
Root node is: Node(QualifiedName(0:Root), ns=0;i=84;)
No match for request
◾ ./a.out 
Connecting to: opc.tcp://10.10.1.16:4840
Root node is: Node(QualifiedName(0:Root), ns=0;i=84;)
No match for request
Root node is: Node(QualifiedName(0:Root), ns=0;i=84;)
Server node obtained by path: Node(QualifiedName(0:Server), ns=0;i=2253;)
Child of objects node are: 
    Node(QualifiedName(0:Server), ns=0;i=2253;)
    Node(QualifiedName(2:DeviceSet), ns=2;i=5001;)
    Node(QualifiedName(4:PLC1), ns=1;s=PLC1;)
NamespaceArray is: 
    http://opcfoundation.org/UA/
    urn:CP-13333C/Beckhoff/TcOpcUaServer/1
    http://opcfoundation.org/UA/DI/
    http://PLCopen.org/OpcUa/IEC61131-3/
    PLC1
  • using the python example, get/set value() appears to work well.
    if I start the demo with 'create_subscription', it updates fine on connect, but the first monitor will raise:
Not enough data was received from channel.

Is there a specific version in git I can use that is more stable?

Project looks encouraging btw. congrats

Won't compile on Raspbian

Trying to get this running (and the python bindings) on the Raspberry Pi as I think @pspeybro has before.

Setup Raspbian Jessie with gcc, g++ cpp 4.9.

Get an error whilst running make. Photo to follow shortly. Really hoping to get this working :)

Cannot write to the node of custom server

Hello,

I have custom server based on Unified Automation SDK and I can not write new value to the node. Writing is possible with UaExpert. Also the example client can write to the example server (provided in this repo).

I tried to debug it with wireshark but I'm not sure for what should I search. I saw there is a quite a difference in data which are sent. Do you have any recommendation how should I proceed?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.