Coder Social home page Coder Social logo

freeopcua / opcua-asyncio Goto Github PK

View Code? Open in Web Editor NEW
981.0 55.0 338.0 15.43 MB

OPC UA library for python >= 3.7

License: GNU Lesser General Public License v3.0

Dockerfile 0.01% Shell 0.01% Python 99.99%
python3 opc-ua asyncio iec62541 protocol opcua

opcua-asyncio's Introduction

OPC UA / IEC 62541 Client and Server for Python >= 3.7 and pypy3 . http://freeopcua.github.io/, https://github.com/FreeOpcUa/opcua-asyncio

Python package

PyPI Package

opcua-asyncio

opcua-asyncio is an asyncio-based asynchronous OPC UA client and server based on python-opcua, removing support of python < 3.7. Asynchronous programming allows for simpler code (e.g. less need for locks) and can potentially provide performance improvements. This library also provides a synchronous wrapper over the async API, which can be used in synchronous code instead of python-opcua.


The OPC UA binary protocol implementation has undergone extensive testing with various OPC UA stacks. The API offers both a low level interface to send and receive all UA defined structures and high level classes allowing to write a server or a client in a few lines. It is easy to mix high level objects and low level UA calls in one application. Most low level code is autogenerated from xml specification.

The test coverage reported by coverage.py is over 95%, with the majority of the non-tested code being autogenerated code that is not currently in use.

Warnings

opcua-asyncio is open-source and comes with absolutely no warranty. We try to keep it as bug-free as possible, and try to keep the API stable, but bugs and API changes will happen! In particular, API changes are expected to take place prior to any 1.0 release.

Some renaming of methods from get_xx to read_xx and set_xx to write_xxx have been made to better follow OPC UA naming conventions

Version 0.9.9 introduces some argument renaming due to more automatic code generation. Especially the arguments to NodeId, BrowseName, LocalizedText and DataValue, which are now CamelCase instead of lower case, following the OPC UA conventions used in all other structures in this library

Installation

With pip

pip install asyncua

Usage

We assume that you already have some experience with Python, the asyncio module, the async / await syntax and the concept of asyncio Tasks.

Client class

The Client class provides a high level API for connecting to OPC UA servers, session management and access to basic address space services. The client can be used as a context manager. The client will then automatically connect and disconnect withing the withsyntax.

from asyncua import Client

async with Client(url='opc.tcp://localhost:4840/freeopcua/server/') as client:
    while True:
        # Do something with client
        node = client.get_node('i=85')
        value = await node.read_value()

Of course, you can also call the connect, disconnect methods yourself if you do not want to use the context manager.

See the example folder and the code for more information on the client API.

Node class

The Node class provides a high level API for management of nodes as well as data access services.

Subscription class

The Subscription class provides a high level API for management of monitored items.

Server class

The Server class provides a high level API for creation of OPC UA server instances.

Documentation

The documentation is available here ReadTheDocs.

The API remains mostly unchanged with regards to python-opcua. The main difference is that most methods are now asynchronous. Please have a look at the examples and/or the code.

A simple GUI client is available at: https://github.com/FreeOpcUa/opcua-client-gui

Browse the examples: https://github.com/FreeOpcUa/opcua-asyncio/tree/master/examples

The minimal examples are a good starting point. Minimal client example: https://github.com/FreeOpcUa/opcua-asyncio/blob/master/examples/client-minimal.py Minimal server example: https://github.com/FreeOpcUa/opcua-asyncio/blob/master/examples/server-minimal.py

A set of command line tools also available: https://github.com/FreeOpcUa/opcua-asyncio/tree/master/tools

  • uadiscover (find_servers, get_endpoints and find_servers_on_network calls)
  • uals (list children of a node)
  • uahistoryread
  • uaread (read attribute of a node)
  • uawrite (write attribute of a node)
  • uacall (call method of a node)
  • uasubscribe (subscribe to a node and print datachange events)
  • uaclient (connect to server and start python shell)
  • uaserver (starts a demo OPC UA server) tools/uaserver --populate --certificate cert.pem --private_key pk.pem

How to generate certificate: https://github.com/FreeOpcUa/opcua-asyncio/tree/master/examples/generate_certificate.sh

Client support

What works:

  • connection to server, opening channel, session
  • browsing and reading attributes value
  • getting nodes by path and nodeids
  • creating subscriptions
  • subscribing to items for data change
  • subscribing to events
  • adding nodes
  • method call
  • user and password
  • history read
  • login with certificate
  • communication encryption
  • removing nodes

Tested servers: freeopcua C++, freeopcua Python, prosys, kepware, beckhoff, winCC, B&R, โ€ฆ

Not implemented yet:

  • localized text feature
  • XML protocol
  • UDP (PubSub stuff)
  • WebSocket
  • maybe automatic reconnection...

Server support

What works:

  • creating channel and sessions
  • read/set attributes and browse
  • getting nodes by path and nodeids
  • autogenerate address space from spec
  • adding nodes to address space
  • datachange events
  • events
  • methods
  • basic user implementation (one existing user called admin, which can be disabled, all others are read only)
  • encryption
  • certificate handling
  • removing nodes
  • history support for data change and events
  • more high level solution to create custom structures

Tested clients: freeopcua C++, freeopcua Python, uaexpert, prosys, quickopc

Not yet implemented:

  • UDP (PubSub stuff)
  • WebSocket
  • session restore
  • alarms
  • XML protocol
  • views
  • localized text features
  • better security model with users and password

Running a server on a Raspberry Pi

Setting up the standard address-space from XML is the most time-consuming step of the startup process which may lead to long startup times on less powerful devices like a Raspberry Pi. By passing a path to a cache-file to the server constructor, a shelve holding the address space will be created during the first startup. All following startups will make use of the cache-file which leads to significantly better startup performance (~3.5 vs 125 seconds on a Raspberry Pi Model B).

Development

Code follows PEP8 apart for line lengths which should be max 160 characters and OPC UA structures that keep camel case from XML definition.

All protocol code is under opcua directory

  • asyncua/ua contains all UA structures from specification, most are autogenerated
  • asyncua/common contains high level objects and methods used both in server and client
  • asyncua/client contains client specific code
  • asyncua/server contains server specific code
  • asyncua/utils contains some utilities function and classes
  • asyncua/tools contains code for command lines tools
  • schemas contains the XML and text files from specification and the python scripts used to autogenerate code
  • tests contains tests
  • docs contains files to auto generate documentation from doc strings
  • examples contains many example files
  • examples/sync contains many example files using sync API
  • tools contains python scripts that can be used to run command line tools from repository without installing

Running tests:

python -m pip install -r requirements.txt
python -m pip install -r dev_requirements.txt
pytest -v -s

Or

./run-test.sh -v -s

Coverage

pytest -v -s --cov asyncua --cov-report=html

Or

./run-test.sh -v -s --cov asyncua --cov-report=html

opcua-asyncio's People

Contributors

aiyionprime avatar alkor avatar andreasheine avatar bitkeeper avatar brubbel avatar chrisjbremner avatar curiouscrook avatar cziebuhr avatar destogl avatar georgschoelly avatar helmut-jacob avatar huazh avatar joeyfaulkner avatar koseng avatar lovasoa avatar maljac avatar mathias-luedtke avatar nebukadneza avatar okapies avatar oroulet avatar rth avatar sanssecours avatar schroeder- avatar smorokin avatar stanti avatar swamper123 avatar vruge avatar yangpeiren avatar zerox1212 avatar zuzud 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

opcua-asyncio's Issues

background tasks and subcriptions

@cbergmiller In fact I was trying to debug exactly that stuff right now. but I am not really sure how to do this correctly. I see that you implemented the connection renewal using create_task and recursion. This kind of fire and forget stuff in asyncio is asking for trouble. I believe, but correct me if I am wrong, that we should have a a background task, keep reference to task, and at the end cancel it and await it. This is easy to do for connectino renewale but much more difficult for subscriptions

I got an error when I got a lot of nodes asyncua.ua.uaerrors._base.UaError: Wrong sequence 518 -> 518 (server bug or replay attack)

I got an error when I got a lot of nodes.
This error is not necessarily happening,It may take a few more runs to happen.
I have a device and thousands of nodes in my kepserver.

stack trace

222Node(StringNodeId(ns=2;s=Collection.ANDON1))
333Node(StringNodeId(ns=2;s=Collection.ANDON1.alarm))
Exception raised while parsing message from server
Traceback (most recent call last):
  File "C:\Python3\lib\site-packages\asyncua\client\ua_client.py", line 68, in _process_received_data
    msg = self._connection.receive_from_header_and_body(header, buf)
  File "C:\Python3\lib\site-packages\asyncua\common\connection.py", line 282, in receive_from_header_and_body
    return self._receive(chunk)
  File "C:\Python3\lib\site-packages\asyncua\common\connection.py", line 299, in _receive
    self._check_incoming_chunk(msg)
  File "C:\Python3\lib\site-packages\asyncua\common\connection.py", line 262, in _check_incoming_chunk
    .format(self._peer_sequence_number, num)
asyncua.ua.uaerrors._base.UaError: Wrong sequence 518 -> 518 (server bug or replay attack)
close_session was called but connection is closed
close_secure_channel was called but connection is closed
disconnect_socket was called but connection is closed
Traceback (most recent call last):
  File "C:/work/async/client-minimal.py", line 31, in <module>
    loop.run_until_complete(main())
  File "C:\Python3\lib\asyncio\base_events.py", line 484, in run_until_complete
    return future.result()
  File "C:/work/async/client-minimal.py", line 23, in main
    for d in await c.get_children():
  File "C:\Python3\lib\asyncio\coroutines.py", line 110, in __next__
    return self.gen.send(None)
  File "C:\Python3\lib\site-packages\asyncua\common\node.py", line 403, in get_referenced_nodes
    references = await self.get_references(refs, direction, nodeclassmask, includesubtypes)
  File "C:\Python3\lib\asyncio\coroutines.py", line 110, in __next__
    return self.gen.send(None)
  File "C:\Python3\lib\site-packages\asyncua\common\node.py", line 382, in get_references
    results = await self.server.browse(params)
  File "C:\Python3\lib\asyncio\coroutines.py", line 110, in __next__
    return self.gen.send(None)
  File "C:\Python3\lib\site-packages\asyncua\client\ua_client.py", line 300, in browse
    data = await self.protocol.send_request(request)
  File "C:\Python3\lib\asyncio\coroutines.py", line 110, in __next__
    return self.gen.send(None)
  File "C:\Python3\lib\site-packages\asyncua\client\ua_client.py", line 122, in send_request
    await asyncio.wait_for(future, timeout if timeout else None)
  File "C:\Python3\lib\asyncio\tasks.py", line 362, in wait_for
    raise futures.TimeoutError()
concurrent.futures._base.TimeoutError

Special handling message id 0 in _call_callback

In case of an _Acknowledge: or an ErrorMessage _call_callback gets always called with an message id of zero. There is no special handling of message id zero in _call_callback though. There will be not future to resolve or cancel with id zero in the callback map.
The right thing to do may be to cancel all request futures (at least in case of a received MessageAbort).
The correct behaviour from the OPC UA spec. has to be implemented.

Can't connect to Rockwell OPCUA server

Hello,
opcua-asyncio version stops with error on connection to server step in async with Client(url=url) as client. At the same time opcua works well.

import asyncio
import sys
sys.path.insert(0, "..")
import logging
from asyncua import Client, Node, ua

logging.basicConfig(level=logging.DEBUG)
_logger = logging.getLogger('asyncua')

async def main():
    url = 'opc.tcp://localhost:4990/FactoryTalkLinxGateway1'
    try:
        async with Client(url=url) as client:
            root = client.get_root_node()
            _logger.info('Objects node is: %r', root)
    except Exception:
        _logger.exception('error')
if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.set_debug(True)
    loop.run_until_complete(main())
    loop.close()

Debug info:
INFO:asyncua.client.client:connect
INFO:asyncua.client.ua_client.UaClient:opening connection
DEBUG:asyncio:Get address info localhost:4990, type=<SocketKind.SOCK_STREAM: 1>
DEBUG:asyncio:Getting address info localhost:4990, type=<SocketKind.SOCK_STREAM: 1> took 0.000ms: [(<AddressFamily.AF_INET6: 23>, <SocketKind.SOCK_STREAM: 1>, 0, '', ('::1', 4990, 0, 0)), (<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 0, '', ('127.0.0.1', 4990))]
DEBUG:asyncio:poll took 0.000 ms: 1 events
DEBUG:asyncio:connect <socket.socket fd=256, family=AddressFamily.AF_INET6, type=SocketKind.SOCK_STREAM, proto=0> to ('::1', 4990, 0, 0)
DEBUG:asyncio:poll took 0.000 ms: 1 events
DEBUG:asyncio:<socket.socket fd=256, family=AddressFamily.AF_INET6, type=SocketKind.SOCK_STREAM, proto=0, laddr=('::1', 50124, 0, 0), raddr=('::1', 4990, 0, 0)> connected to localhost:4990: (<_SelectorSocketTransport fd=256 read=polling write=<idle, bufsize=0>>, <asyncua.client.ua_client.UASocketProtocol object at 0x037A7FF0>)
DEBUG:asyncio:poll 4000.000 ms took 0.000 ms: 1 events
INFO:asyncua.client.ua_client.UASocketProtocol:open_secure_channel
DEBUG:asyncua.client.ua_client.UASocketProtocol:Sending: OpenSecureChannelRequest(TypeId:FourByteNodeId(i=446), RequestHeader:RequestHeader(AuthenticationToken:TwoByteNodeId(i=0), Timestamp:2019-02-24 08:55:37.973007, RequestHandle:1, ReturnDiagnostics:0, AuditEntryId:None, TimeoutHint:1000, AdditionalHeader:ExtensionObject(TypeId:TwoByteNodeId(i=0), Encoding:0, None bytes)), Parameters:OpenSecureChannelParameters(ClientProtocolVersion:0, RequestType:0, SecurityMode:1, ClientNonce:b'', RequestedLifetime:3600000))
DEBUG:asyncio:poll 4000.000 ms took 0.000 ms: 1 events
INFO:asyncua.client.ua_client.UaClient:create_session
DEBUG:asyncua.client.ua_client.UASocketProtocol:Sending: CreateSessionRequest(TypeId:FourByteNodeId(i=461), RequestHeader:RequestHeader(AuthenticationToken:TwoByteNodeId(i=0), Timestamp:2019-02-24 08:55:37.975007, RequestHandle:2, ReturnDiagnostics:0, AuditEntryId:None, TimeoutHint:10, AdditionalHeader:ExtensionObject(TypeId:TwoByteNodeId(i=0), Encoding:0, None bytes)), Parameters:CreateSessionParameters(ClientDescription:ApplicationDescription(ApplicationUri:urn:freeopcua:client, ProductUri:urn:freeopcua.github.io:client, ApplicationName:LocalizedText(Encoding:2, Locale:None, Text:Pure Python Async. Client), ApplicationType:1, GatewayServerUri:None, DiscoveryProfileUri:None, DiscoveryUrls:[]), ServerUri:None, EndpointUrl:opc.tcp://localhost:4990/FactoryTalkLinxGateway1, SessionName:Pure Python Async. Client Session1, ClientNonce:b'\xe4IK\x81E\x10\xdf&\xff\xdaY\xc5\x9cc\xa1\xa6\xc0\xff\xbd\xcbN\xff\x91\x12J\xacJ\xbe\x9b\xba\xe7\x95', ClientCertificate:None, RequestedSessionTimeout:3600000, MaxResponseMessageSize:0))
DEBUG:asyncio:poll 10000.000 ms took 0.000 ms: 1 events

INFO:asyncua.client.client:find_endpoint [EndpointDescription(EndpointUrl:opc.tcp://localhost:4990/FactoryTalkLinxGateway1, Server:ApplicationDescription(ApplicationUri:urn:TEMP09-81OV7KU9:FactoryTalk Linx Gateway OPC UA Server, ProductUri:urn:FactoryTalk Linx Gateway OPC UA Server, ApplicationName:LocalizedText(Encoding:3, Locale:en, Text:FactoryTalkLinxGateway), ApplicationType:0, GatewayServerUri:None, DiscoveryProfileUri:None, DiscoveryUrls:['opc.tcp://localhost:4990/FactoryTalkLinxGateway1']), ServerCertificate:[...cuted...] , SecurityMode:1, SecurityPolicyUri:http://opcfoundation.org/UA/SecurityPolicy#None, UserIdentityTokens:[UserTokenPolicy(PolicyId:Anonymous_Policy, TokenType:0, IssuedTokenType:None, IssuerEndpointUrl:None, SecurityPolicyUri:None)], TransportProfileUri:http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary, SecurityLevel:11)] <MessageSecurityMode.None_: 1> 'http://opcfoundation.org/UA/SecurityPolicy#None'
INFO:asyncua.client.ua_client.UaClient:activate_session
DEBUG:asyncua.client.ua_client.UASocketProtocol:Sending: ActivateSessionRequest(TypeId:FourByteNodeId(i=467), RequestHeader:RequestHeader(AuthenticationToken:ByteStringNodeId(b=b'\x1an]\xd6[\x04&\x95!w\xb5\x98\xb53\xa0g2\A<\xc1\xd8\xb9\x10\x9e\x0b\xdf\x10\xea\x00,j'), Timestamp:2019-02-24 08:55:37.979007, RequestHandle:3, ReturnDiagnostics:0, AuditEntryId:None, TimeoutHint:10, AdditionalHeader:ExtensionObject(TypeId:TwoByteNodeId(i=0), Encoding:0, None bytes)), Parameters:ActivateSessionParameters(ClientSignature:SignatureData(Algorithm:http://www.w3.org/2000/09/xmldsig#rsa-sha1, Signature:b''), ClientSoftwareCertificates:[], LocaleIds:['en'], UserIdentityToken:AnonymousIdentityToken(PolicyId:Anonymous_Policy), UserTokenSignature:SignatureData(Algorithm:None, Signature:None)))
DEBUG:asyncio:poll 10000.000 ms took 78.000 ms: 1 events
WARNING:asyncua.client.ua_client.UASocketProtocol:ServiceFault from server received in response to ActivateSessionRequest
ERROR:asyncua:error
Traceback (most recent call last):
File "C:\Users\Labuser\git\opcua-asyncio\examples\client-minimal_my.py", line 14, in main
async with Client(url=url) as client:
File "..\asyncua\client\client.py", line 65, in aenter
await self.connect()
File "..\asyncua\client\client.py", line 209, in connect
await self.activate_session(username=self._username, password=self._password, certificate=self.user_certificate)
File "..\asyncua\client\client.py", line 404, in activate_session
return await self.uaclient.activate_session(params)
File "..\asyncua\client\ua_client.py", line 272, in activate_session
data = await self.protocol.send_request(request)
File "..\asyncua\client\ua_client.py", line 124, in send_request
self.check_answer(data, " in response to " + request.class.name)
File "..\asyncua\client\ua_client.py", line 133, in check_answer
hdr.ServiceResult.check()
File "..\asyncua\ua\uatypes.py", line 224, in check
raise UaStatusCodeError(self.value)
asyncua.ua.uaerrors._auto.BadTimeout: The operation timed out.(BadTimeout)
DEBUG:asyncio:Close <_WindowsSelectorEventLoop running=False closed=False debug=True>
ERROR:asyncio:Task was destroyed but it is pending!
source_traceback: Object created at (most recent call last):
File "C:\Users\Labuser\git\opcua-asyncio\examples\client-minimal_my.py", line 24, in
loop.run_until_complete(main())
File "C:\Users\Labuser\AppData\Local\Programs\Python\Python37-32\lib\asyncio\base_events.py", line 571, in run_until_complete
self.run_forever()
File "C:\Users\Labuser\AppData\Local\Programs\Python\Python37-32\lib\asyncio\base_events.py", line 539, in run_forever
self._run_once()
File "C:\Users\Labuser\AppData\Local\Programs\Python\Python37-32\lib\asyncio\base_events.py", line 1767, in _run_once
handle._run()
File "C:\Users\Labuser\AppData\Local\Programs\Python\Python37-32\lib\asyncio\events.py", line 88, in _run
self._context.run(self._callback, *self._args)
File "C:\Users\Labuser\git\opcua-asyncio\examples\client-minimal_my.py", line 14, in main
async with Client(url=url) as client:
File "..\asyncua\client\client.py", line 65, in aenter
await self.connect()
File "..\asyncua\client\client.py", line 204, in connect
await self.create_session()
File "..\asyncua\client\client.py", line 340, in create_session
self._renew_channel_task = self.loop.create_task(self._renew_channel_loop())
task: <Task pending coro=<Client._renew_channel_loop() running at ..\asyncua\client\client.py:353> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x0383E710>()] created at C:\Users\Labuser\AppData\Local\Programs\Python\Python37-32\lib\asyncio\base_events.py:396> created at ..\asyncua\client\client.py:340>

Support single handle or list of handles in Subscription.unsubscribe()

Since e.g. Subscription.subscribe_data_change() returns a list of handles it would be nice if Subscription.unsubscribe() would accept this list in addition to a single handle.
This requires minimal code changes. Typings for the handle parameters could further help to clarify the usage of the subscription handles.

Missing await in server.link_method

I get RuntimeWarning: coroutine 'InternalSession.add_method_callback' was never awaited message when using the link_method() function of server.py
This works for me:

async def link_method(self, node, callback):
"""
Link a python function to a UA method in the address space; required when a UA method has been imported
to the address space via XML; the python executable must be linked manually
:param node: UA method node
:param callback: python function that the UA method will call
"""
await self.iserver.isession.add_method_callback(node.nodeid, callback)

Type hints

I would like to propose the usage of type hints https://www.python.org/dev/peps/pep-0484/ (at least for the complex types).

For example:

    def publish_callback(self, publishresult: ua.PublishResult):
        self.logger.info("Publish callback called with result: %s", publishresult)
        if self.subscription_id is None:
            self.subscription_id = publishresult.SubscriptionId

This could make it easier to understand the code and to enable static type checking (with some IDEs).
It should work fine with python 3.5 and above.
Are there any reservations against the usage of type hints in this project?

Subscription mechanism and Publish on binary HTTPS server ?

Hi,

I'm trying to implement binary/https opc-ua server by using Tornado https server. But I don't know how subscription mechanism should be processed over HTTPS that is a stateless protocol.
How is processed a publish request ? How is sent a publish response ? (Maybe Websocket ?)

Have you an idea about this subject ?

Syntax Error: Client examples

I've installed Python 3.7 and 3.6 but I'm not able to run the example client code from the documentation.

from asyncua import Client

async with Client(url='opc.tcp://172.16.3.51:4840/freeopcua/server/') as client:
    while True:
        # Do something with client
        node = client.get_node('i=85')
        value = await node.get_value()

The Error message for Python 3.7:

  File "test.py", line 3
    async with Client(url='opc.tcp://172.16.3.51:4840/freeopcua/server/') as client:
    ^
SyntaxError: 'async with' outside async function

The Error message for Python3.6:

  File "test.py", line 3
    async with Client(url='opc.tcp://172.16.3.51:4840/freeopcua/server/') as client:
             ^
SyntaxError: invalid syntax

Is the documentation outdated or am I doing something wrong?

Accept SecurityTokens for some time after they expire in SecureConnection

At the moment SecureConnection._check_incoming_chunk checks if the SecurityToken that was received along a message is the current token or if it is a valid previous token.
If it is an previous token than all even older tokens are removed and thus declared invalid (if there are any). I don't think this behaviour conforms to the Specification. Tokens could be removed while they still should be considered valid.

From the Specification:

SecurityTokens have a finite lifetime negotiated with this Service. However, differences between the system clocks on different machines and network latencies mean that valid Messages could arrive after the token has expired. To prevent valid Messages from being discarded, the applications should do the following:

  • Clients should request a new SecurityToken after 75 % of its lifetime has elapsed. This should ensure that Clients will receive the new SecurityToken before the old one actually expires.
  • Servers shall use the existing SecurityToken to secure outgoing Messages until the SecurityToken expires or the Server receives a Message secured with a new SecurityToken. This should ensure that Clients do not reject Messages secured with the new SecurityToken that arrive before the Client receives the new SecurityToken.
  • Clients should accept Messages secured by an expired SecurityToken for up to 25 % of the token lifetime. This should ensure that Messages sent by the Server before the token expired are not rejected because of network delays.

I think we should refactor SecureConnection and implement the 25 % token lifetime check, after which the token is removed from the _old_tokens list.
Invalid tokens are currently ignored and only a warning is logged. This may pose a security risk? At some point in the past an uaError was raised if an invalid token was received. Did this cause too much trouble? Maybe we should make the behaviour configurable (log warning or raise uaError).

[Bug Report] Kepware (and OPC Expert) can't read tags from Python OPC Server

Hi

I have a UA OPC Server running in python (using the server-example.py) python script.

I am able to read tags from the server using one of the example client scripts.

In Kepware I get an error when I try to add browsed tags and when I try to manually add tags using their address I am also not able to view the tags.

Using OPC Expert I get another error (not sure how related they are, error messages seem different)

Python
I am running server-example.py

Kepware:
I add a UA Client channel with the following settings:
image
image
I can browse tags and all looks good
image
But when I click OK, Kepware GUI either crashes without an error message, or I get the following message "Failed to browse tags"

I then don't try to add any tags, and use the default device settings:
image
Then manually add a tag using its address:
image
But the tag doesn't work:
image
(OPC Expert shows that there is an error "Not Connected 8")

OPC Expert
By default the python OPC Server doesn't show up
image
I manually add it using:
image
It adds the server and it looks good:
image

It doesn't connect, the logs show:
image

sync API

It would be great to make a sync API so we do not need to maintain two branches. I am expected many users to be more than happy with sync and not everybody want to use asyncio. If we do that we may not even need to port all examples and tests

It should be possible (and little work) to make wrapper around Client, Server, Subscription and Node classes. the wrapper will also need to make sure that SyncNode returns a SyncNode and AsyncNode objects. some code is there, maybe it can almost be used AS IS. I am not understand everything there, it might be over complicated..

Test `test_xml_method` is failing.

When trying to re-import the nodes from the created XML file, the tests fails with the error BadParentNodeIdInvalid: The parent node id does not to refer to a valid node.(BadParentNodeIdInvalid).

Kepware tag browsing issue

Hi

I'm running an OPC Server in python (server-example.py) and trying to connect to it using an OPC UA Client in Kepware (KEPServerEX6). The connection works but I get an error message when I browse for tags and try to add them. If I manually try to add them using their address (eg. ns=2;i=13) then it works fine.

Browsing for Python OPC Server works:
image

Connection settings (password is blank):
image

I can then browse for tags and it shows all of the tags that should be there:
image

If I then select one/many of the tags I get the following error message:
image

Afterwards I can manually go and and tags which works fine.

Am I missing something on the python side? Or is it maybe some Kepware related issue?

Some log from pycharm:
INFO:asyncua.server.internal_server:Created internal session ('127.0.0.1', 65001)
INFO:asyncua.server.internal_server:Create session request
INFO:asyncua.server.internal_server:get endpoint
INFO:asyncua.server.uaprocessor:sending create session response
INFO:asyncua.server.uaprocessor:Activate session request
INFO:asyncua.server.internal_server:activate session
INFO:asyncua.server.internal_server:Activated internal session ('127.0.0.1', 65001) for user User.Anonymous
INFO:asyncua.server.uaprocessor:sending read response
INFO:asyncua.server.uaprocessor:Read request
INFO:asyncua.server.uaprocessor:sending read response
INFO:asyncua.server.uaprocessor:Browse request
INFO:asyncua.server.uaprocessor:sending browse response
INFO:asyncua.server.uaprocessor:Browse request
INFO:asyncua.server.uaprocessor:sending browse response
INFO:asyncua.server.uaprocessor:Read request
INFO:asyncua.server.uaprocessor:sending read response
INFO:asyncua.server.uaprocessor:Read request
INFO:asyncua.server.uaprocessor:sending read response
INFO:asyncua.server.uaprocessor:Read request
INFO:asyncua.server.uaprocessor:sending read response
INFO:asyncua.server.uaprocessor:Read request
INFO:asyncua.server.uaprocessor:sending read response
INFO:asyncua.server.uaprocessor:Browse request
INFO:asyncua.server.uaprocessor:sending browse response
INFO:asyncua.server.uaprocessor:Read request
INFO:asyncua.server.uaprocessor:sending read response
INFO:asyncua.server.uaprocessor:Close session request
!! This comes after I try to add the tags from the browse menu
INFO:asyncua.server.internal_server:close session %s
INFO:asyncua.server.subscription_service:delete subscriptions: []
INFO:asyncua.server.uaprocessor:sending close session response
INFO:asyncua.server.binary_server_asyncio:processor returned False, we close connection from ('127.0.0.1', 65001)
INFO:asyncua.server.binary_server_asyncio:Lost connection from ('127.0.0.1', 65001), None
INFO:asyncua.server.uaprocessor:Cleanup client connection: ('127.0.0.1', 65001)
INFO:asyncua.server.internal_server:close session %s
INFO:asyncua.server.subscription_service:delete subscriptions: []

missing tests from python-opcua

@cbergmiller do you have any overview of what tests are missing in asyncua compared to python-opcua? Now that I have sync wrapper that seem to completely working, it should in theary be possible to just copy the missing files to this repository, although it would be better to port them to pytest too

sync-api

should we have explicit start_thread_loop() and stop_thread_loop() or can we hide it in del etc... hidding it might generate some fancy error cases....

Error when trying to set_value() of a tag

Hi

I'm getting an error when I try to set a value using set_value() in a client.

I have a Kepware UA OPC Server running and connecting using a simple UA Client in python

When I try to use:
tag1.set_value(5)
I get:
asyncua.ua.uaerrors._auto.BadWriteNotSupported: The server does not support writing the combination of value, status and timestamps provided.(BadWriteNotSupported)

I read some of the previous issues, so I then tried a few more options:
dv = ua.DataValue(5, ua.VariantType.UInt16)
dv.ServerTimestamp = datetime.now()
await tag1.set_value(dv)
and
await tag1.set_attribute(ua.AttributeIds.Value, ua.Variant(value=5))

and a few other combinations but I keep getting the error:

AttributeError: 'Variant' object has no attribute 'ua_types'
or
AttributeError: 'VariantType' object has no attribute 'ua_types'

(I am able to set the value of the same tag using another UA Client)

Stacktrace
ERROR:asyncua:error
Traceback (most recent call last):
File "K:/repos/opcua-asyncio/examples/client-example.py", line 72, in run
await tag1.set_value(dv)
File "C:\Miniconda2\envs\python_opc\lib\asyncio\coroutines.py", line 110, in next
return self.gen.send(None)
File "K:\repos\opcua-asyncio\asyncua\common\node.py", line 228, in set_value
await self.set_attribute(ua.AttributeIds.Value, datavalue)
File "C:\Miniconda2\envs\python_opc\lib\asyncio\coroutines.py", line 110, in next
return self.gen.send(None)
File "K:\repos\opcua-asyncio\asyncua\common\node.py", line 273, in set_attribute
result = await self.server.write(params)
File "C:\Miniconda2\envs\python_opc\lib\asyncio\coroutines.py", line 110, in next
return self.gen.send(None)
File "K:\repos\opcua-asyncio\asyncua\client\ua_client.py", line 340, in write
data = await self.protocol.send_request(request)
File "C:\Miniconda2\envs\python_opc\lib\asyncio\coroutines.py", line 110, in next
return self.gen.send(None)
File "K:\repos\opcua-asyncio\asyncua\client\ua_client.py", line 120, in send_request
future = self._send_request(request, callback, timeout, message_type)
File "K:\repos\opcua-asyncio\asyncua\client\ua_client.py", line 99, in _send_request
binreq = struct_to_binary(request)
File "K:\repos\opcua-asyncio\asyncua\ua\ua_binary.py", line 247, in struct_to_binary
packet.append(to_binary(uatype, val))
File "K:\repos\opcua-asyncio\asyncua\ua\ua_binary.py", line 270, in to_binary
return struct_to_binary(val)
File "K:\repos\opcua-asyncio\asyncua\ua\ua_binary.py", line 242, in struct_to_binary
packet.append(list_to_binary(uatype[6:], val))
File "K:\repos\opcua-asyncio\asyncua\ua\ua_binary.py", line 282, in list_to_binary
pack = [to_binary(uatype, el) for el in val]
File "K:\repos\opcua-asyncio\asyncua\ua\ua_binary.py", line 282, in
pack = [to_binary(uatype, el) for el in val]
File "K:\repos\opcua-asyncio\asyncua\ua\ua_binary.py", line 270, in to_binary
return struct_to_binary(val)
File "K:\repos\opcua-asyncio\asyncua\ua\ua_binary.py", line 247, in struct_to_binary
packet.append(to_binary(uatype, val))
File "K:\repos\opcua-asyncio\asyncua\ua\ua_binary.py", line 260, in to_binary
return pack_uatype(vtype, val)
File "K:\repos\opcua-asyncio\asyncua\ua\ua_binary.py", line 179, in pack_uatype
return struct_to_binary(value)
File "K:\repos\opcua-asyncio\asyncua\ua\ua_binary.py", line 247, in struct_to_binary
packet.append(to_binary(uatype, val))
File "K:\repos\opcua-asyncio\asyncua\ua\ua_binary.py", line 260, in to_binary
return pack_uatype(vtype, val)
File "K:\repos\opcua-asyncio\asyncua\ua\ua_binary.py", line 179, in pack_uatype
return struct_to_binary(value)
File "K:\repos\opcua-asyncio\asyncua\ua\ua_binary.py", line 239, in struct_to_binary
for name, uatype in obj.ua_types:
AttributeError: 'VariantType' object has no attribute 'ua_types'
INFO:asyncua.client.ua_client.UASocketProtocol:Socket has closed connection

memory leack in UaSocketProtocol

_callbackmap is never emptied! it might be possible to simply remove objects after a callback is used, but isnt'it any cases where _callbackmap is reused? I am thinking at subscriptions for examples.... @cbergmiller

BadWriteNotSupported

I am trying to write value to opcua.

Basically my code is like this in example:

var = client.get_node("ns=3;i=2002")
print(var)
var.get_data_value() # get value of node as a DataValue object
var.get_value() # get value of node as a python builtin
var.set_value(3.9) # set node value using implicit data type

but I get this error:
asyncua.ua.uaerrors._auto.BadWriteNotSupported: The server does not support writing the combination of value, status and
timestamps provided.(BadWriteNotSupported)

Should I be using this instead:
var.set_value(ua.Variant([23], ua.VariantType.Int64)) #set node value using explicit data type

If so, what is best way to make sure that VariantType is right? I can have bool, float, int16,int32 and string. Surely I can make my own function to check it I think, but is there better way?

BadTimeout Error connecting to Frako PQM-1588 OPC-UA DA Server

opcua.ua.uaerrors._auto.BadTimeout: The operation timed out.(BadTimeout)
For a better understandig, with the asyncronious client I get that timeout error. See attachment of the output.dump file
output.zip

The client IP is 10.2.202.253, the Server IP is 10.2.202.200.
Authentification method is anonymous, no encryption, no username&password

Exception:
File "/python-opcua/asyncua/common/node.py", line 149, in get_node_class result = await self.get_attribute(ua.AttributeIds.NodeClass)
File "/coroutines.py", line 109, in __next__
File "/python-opcua/asyncua/common/node.py", line 286, in get_attribute result = await self.server.read(params)
File "/coroutines.py", line 109, in __next__
File "/python-opcua/asyncua/client/ua_client.py", line 320, in read data = await self.protocol.send_request(request)
File "/coroutines.py", line 109, in __next__
File "/python-opcua/asyncua/client/ua_client.py", line 122, in send_request await asyncio.wait_for(future, timeout if timeout else None)
File "/tasks.py", line 362, in wait_for concurrent.futures._base.TimeoutError

If testing a connection with the software UaExpert V1.4.4 to the same OPC-UA Server everything is good
pqm-1588
output.zip

Future for request id {request_id} is already done

I created a thread (from threading import Thread) for loop in order to run asyncio it with Qt. I do a lot (1000/Sec) of
asyncio.run_coroutine_threadsafe(node.setvalue(), loop) .
In some circumstances I got an error. May be it's something obvious for you guys what can be wrong?

ERROR:asyncua.client.ua_client.UASocketProtocol:Exception raised while parsing message from server
Traceback (most recent call last):
File "C:\Users\Labuser\AppData\Local\Programs\Python\Python37-32\lib\site-packages\asyncua\client\ua_client.py", line 152, in _call_callback
self._callbackmap[request_id].set_result(body)
asyncio.base_futures.InvalidStateError: invalid state

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:\Users\Labuser\AppData\Local\Programs\Python\Python37-32\lib\site-packages\asyncua\client\ua_client.py", line 79, in _process_received_data
self._process_received_message(msg)
File "C:\Users\Labuser\AppData\Local\Programs\Python\Python37-32\lib\site-packages\asyncua\client\ua_client.py", line 93, in _process_received_message
self._call_callback(msg.request_id(), msg.body())
File "C:\Users\Labuser\AppData\Local\Programs\Python\Python37-32\lib\site-packages\asyncua\client\ua_client.py", line 158, in _call_callback
raise ua.UaError(f"Future for request id {request_id} is already done")
asyncua.ua.uaerrors._base.UaError: Future for request id 2458 is already done

history data are never saved in sqlite database

Hello,

I try do test history feature on the asyncio-server unsuccessfully.

I use the server-datavalue-history.py example script that I modify like this:

import asyncio
import sys
sys.path.insert(0, "..")
import time
import math


from asyncua import ua, Server
from asyncua.server.history_sql import HistorySQLite


async def main():

    # setup our server
    server = Server()
    
    # Configure server to use sqlite as history database (default is a simple memory dict)
    server.iserver.history_manager.set_storage(HistorySQLite("my_datavalue_history.sql"))
    
    # initialize server 
    await server.init()

    server.set_endpoint("opc.tcp://0.0.0.0:4840/freeopcua/server/")

    # setup our own namespace, not really necessary but should as spec
    uri = "http://examples.freeopcua.github.io"
    idx = await server.register_namespace(uri)

    # get Objects node, this is where we should put our custom stuff
    objects = server.get_objects_node()

    # populating our address space
    myobj = await objects.add_object(idx, "MyObject")
    myvar = await myobj.add_variable(idx, "MyVariable", ua.Variant(0, ua.VariantType.Double))
    await myvar.set_writable()  # Set MyVariable to be writable by clients
    print(myvar)

    # starting!
    await server.start()

    # enable data change history for this particular node, must be called after start since it uses subscription
    await server.historize_node_data_change(myvar, period=None, count=100)

    try:
        count = 0
        while True:
            time.sleep(1)
            count += 0.1
            await myvar.set_value(math.sin(count))
            print(count)

    finally:
        # close connection, remove subscriptions, etc
        await server.stop()

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.set_debug(True)
    loop.run_until_complete(main())

The data are never saved in sqlite3 database.

Has someone already had this problem?

lost exception in AttributeService.write

@cbergmiller I found this one: 3126dc8
This fixes one bug, BUT there is one more. If an exception is raised at that line in code, then the write call hangs forever, nothing printed in stdout and nothing is sent back to client. It looks like the exception is lost in some asyncio tasks?!?!?
If you have two minutes it would be great if you could have a look.

UaStatusCodeError(self.value) after a fixed time

Hi guys,

I am trying to make the opcua subscription working with the code below. The code is just the same as is in the example folder. (ofcourse there are some adjustments for making it work on my hardware) But after a fixed time, approximately 10 secs it comes with the following error.

When I play with the sleep (await asyncio.sleep(10)) time, for example putting it to 500, it keeps on running for about 8 minutes before it will show up with the same error.

Is this something on my site wrong or can it be a issue/bug?

import time
import asyncio
import logging

from asyncua import Client

logging.basicConfig(level=logging.INFO)
_logger = logging.getLogger('asyncua')
import datetime

class SubHandler(object):
    """
    Subscription Handler. To receive events from server for a subscription
    data_change and event methods are called directly from receiving thread.
    Do not do expensive, slow or network operation there. Create another 
    thread if you need to do such a thing
    """

    def datachange_notification(self, node, val, data):
        print("New data change event", node, val, data)


    def event_notification(self, event):
        print("New event", event)


async def run():
    url = "opc.tcp://192.168.150.1:4840/"
    try:
        async with Client(url=url) as client:
            root = client.get_root_node()
            _logger.info("Root node is: %r", root)
            objects = client.get_objects_node()
            _logger.info("Objects node is: %r", objects)

            # Node objects have methods to read and write node attributes as well as browse or populate address space
            _logger.info("Children of root are: %r", await root.get_children())

            uri = "urn:OMRON:NxOpcUaServer:FactoryAutomation"
            idx = await client.get_namespace_index(uri)
            _logger.info("index of our namespace is %s", idx)


            Counter = await root.get_child(["0:Objects", f"{idx}:new_Controller_0", "3:GlobalVars", "4:Counter"])

            obj = await root.get_child(["0:Objects", "4:new_Controller_0", "3:GlobalVars",])
            _logger.info("myvar is: %r", Counter)

            handler = SubHandler()
            sub = await client.create_subscription(500, handler)
            vars = [Counter]

            handle = await sub.subscribe_data_change(vars)
            await asyncio.sleep(10)

    except Exception:
        _logger.exception('error')


tijd_gestart = datetime.datetime.now()
_logger.info("Time start: {}".format(tijd_gestart))

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.set_debug(False)
    loop.run_until_complete(run())
    tijd_gestopt = datetime.datetime.now()
    _logger.info("Tijdsduur: {}".format(tijd_gestopt-tijd_gestart))

uatypes.py

    def check(self):
        """
        Raises an exception if the status code is anything else than 0 (good).

        Use the is_good() method if you do not want an exception.
        """
        if not self.is_good():
            print("Value",self.value)
            raise UaStatusCodeError(self.value)

Python Console

Value 2149974016
INFO:asyncua.client.ua_client.UaClient:call_publish_callback
WARNING:asyncua.client.ua_client.UASocketProtocol:ServiceFault from server received while waiting for publish response
ERROR:asyncio:Task exception was never retrieved
future: <Task finished coro=<UaClient._call_publish_callback() done, defined at D:\projects\opc\lib\site-packages\asyncua\client\ua_client.py:468> exception=BadSessionClosed(2149974016)>
Traceback (most recent call last):
  File "D:\projects\opc\lib\site-packages\asyncua\client\ua_client.py", line 471, in _call_publish_callback
    self.protocol.check_answer(data, "while waiting for publish response")
  File "D:\projects\opc\lib\site-packages\asyncua\client\ua_client.py", line 133, in check_answer
    hdr.ServiceResult.check()
  File "D:\projects\opc\lib\site-packages\asyncua\ua\uatypes.py", line 225, in check
    raise UaStatusCodeError(self.value)
asyncua.ua.uaerrors._auto.BadSessionClosed: The session was closed by the client.(BadSessionClosed)
INFO:asyncua.client.ua_client.UASocketProtocol:close_secure_channel
INFO:asyncua.client.ua_client.UASocketProtocol:Request to close socket received
INFO:asyncua.client.ua_client.UASocketProtocol:Socket has closed connection
INFO:asyncua:Tijdsduur: 0:00:10.078220	

Await datachange?

Is there a possibility to create a subscription and await data changes (in an endless loop) instead of triggering the datachange_notification method in a subscription handler class?

Next planned release?

Hi, I am in the process of converting our codebase from python-opcua, and we rely on a feature to be able to pass in an event loop into the server from this commit.

I noticed this is not in 0.5.0. When is the next planned release?

Long-running loop sees internal subscription processing error

Hi,

We're using a long-running client subscription loop which connects to a SIMATIC WinCC OA server in order to log events.

After several days, an error internal to the library is raised, which does not propagate to the subscriber handler. As a result, the entire process stops logging events, while the subscriber continues on its loop without a clue that something has gone wrong.

We're using asyncua == 0.5.0.

The entire context is guarded to facilitate a clean exit in case of trouble:

        async with self.client:
            try:
            except:

Yet nothing gets through to break off the client subscription.

The only output is a short trace:

11:37:16 [WARNING] asyncua.uaprotocol - Received an error: MessageAbort(error:StatusCode(Good), reason:None)
11:37:16 [CRITICAL] asyncua.client.ua_client.UASocketProtocol - Received an error: MessageAbort(error:StatusCode(Good), reason:None)
11:37:16 [ERROR] asyncua.client.ua_client.UASocketProtocol - Exception raised while parsing message from server
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/asyncua/client/ua_client.py", line 69, in _process_received_data
    self._process_received_message(msg)
  File "/usr/local/lib/python3.7/site-packages/asyncua/client/ua_client.py", line 86, in _process_received_message
    self._call_callback(0, ua.UaStatusCodeError(msg.Error.value))
  File "/usr/local/lib/python3.7/site-packages/asyncua/client/ua_client.py", line 141, in _call_callback
    request_id, self._callbackmap.keys()))
asyncua.ua.uaerrors._base.UaError: No request found for requestid: 0, callbacks in list are dict_keys([7333, 7334])

We're a bit stumped. One option on the table is to fall back to the synchronous library, as this seems very black box. The last version published seems 0.5.0 on PyPI; has there been a more recent update we can try?

Your feedback would be appreciated!

Kind regards,
Dann

Datachange not acknowledged in History

Hello,

I try to test history function and I use server-datavalue-history.py from #63 . I see in log information that the datachange notifications are never acknowledged: see attached file:
log.txt

We see that AvailableSequenceNumbers list is growing up indefinitely with opcua-asyncio whereas a publish request with acks is generated with python-opcua

Have you an idea about this issue ?

N.B: I run server example without connected client.

NodeId of type GUID that is parsed from string can't be converted to binary

When try to use a Node that is instantiated wit a GUID type string:

var = client.get_node("ns=4;g=35d5f86f-2777-4550-9d48-b098f5ee285c")

an exception is raised when it is converted to binary:

Traceback (most recent call last):
  File "client-minimal.py", line 30, in main
    print("My variable", var, await var.get_value())
  File "..\asyncua\common\node.py", line 164, in get_value
    result = await self.get_data_value()
  File "..\asyncua\common\node.py", line 173, in get_data_value
    return await self.get_attribute(ua.AttributeIds.Value)
  File "..\asyncua\common\node.py", line 284, in get_attribute
    result = await self.server.read(params)
  File "..\asyncua\client\ua_client.py", line 343, in read
    data = await self.protocol.send_request(request)
  File "..\asyncua\client\ua_client.py", line 134, in send_request
    self._send_request(request, timeout, message_type),
  File "..\asyncua\client\ua_client.py", line 114, in _send_request
    binreq = struct_to_binary(request)
  File "..\asyncua\ua\ua_binary.py", line 246, in struct_to_binary
    packet.append(to_binary(uatype, val))
  File "..\asyncua\ua\ua_binary.py", line 269, in to_binary
    return struct_to_binary(val)
  File "..\asyncua\ua\ua_binary.py", line 241, in struct_to_binary
    packet.append(list_to_binary(uatype[6:], val))
  File "..\asyncua\ua\ua_binary.py", line 281, in list_to_binary
    pack = [to_binary(uatype, el) for el in val]
  File "..\asyncua\ua\ua_binary.py", line 281, in <listcomp>
    pack = [to_binary(uatype, el) for el in val]
  File "..\asyncua\ua\ua_binary.py", line 269, in to_binary
    return struct_to_binary(val)
  File "..\asyncua\ua\ua_binary.py", line 246, in struct_to_binary
    packet.append(to_binary(uatype, val))
  File "..\asyncua\ua\ua_binary.py", line 259, in to_binary
    return pack_uatype(vtype, val)
  File "..\asyncua\ua\ua_binary.py", line 175, in pack_uatype
    return nodeid_to_binary(value)
  File "..\asyncua\ua\ua_binary.py", line 302, in nodeid_to_binary
    Primitives.Guid.pack(nodeid.Identifier)
  File "..\asyncua\ua\ua_binary.py", line 90, in pack
    f1 = Primitives.UInt32.pack(guid.time_low)
AttributeError: 'str' object has no attribute 'time_low'

In Node._from_string() the uid string is used as identifier. I guess it should be parsed as UUID instance instead. A test for guid NodeIds from strings should also be added.

No access to server with Bosch Rexroth OPC UA test client

I've started one of your simple server examples.
I have easy access with your own provided client.
I also have access with some Android Apps.
If I try with the test client, provided by Bosch Rexroth, then I can't manage to get a connection to my server.
https://www.boschrexroth.com/en/xc/products/product-groups/electric-drives-and-controls/industrial-iot/iot-gateway
You have to scroll down to "Downloads" and download the OPC UA Client from there.
I was not able to find out why the connection always fails but I think you have better ways of debugging.

is returning a coroutine from sync methods really more efficient flagging that method async?

@cbergmiller is returning a coroutine from sync methods really more efficient flagging that method async?

I see that you often do not declare methods returning coroutine with async....

Is really

async def toto():
    await asyncio.sleep(1)

def whaterver():
    return toto()

await whatever

faster than

async def toto():
    await asyncio.sleep(1)

async def whaterver():
    return toto()

await whatever()

?

I am expecting python to create exactly ONE task when calling whatever() independantly if it is flagged with async or not. But the first version is much less readable since we do not have async declaration

SourceTimestamp and ServerTimestamp created as naive Datetime?

In async.ua.uatypes at line 21 we have:

FILETIME_EPOCH_AS_DATETIME = datetime(1601, 1, 1)

I am happy to be corrected, but to me this creates what the Python documentation calls a naive datetime, that is, without time zone information, and this will return the time local to my time zone.

In other words, these return different results; shouldn't the last one be used?

datetime(1601,1,1).timestamp()
datetime(1601,1,1,tzinfo=timezone.utc).timestamp()

(All timestamps in the OPC UA standard are in UTC, AFAIK)

All subscriptions on server are deleted when a client session is closed

My application creates several driver client instances connected to the same OPC server. An issue I found migrating from python-opcua is that every time a client session is closed, the other connected clients would stop getting updates from their subscriptions.

After digging through the code a bit, I found that the the close_session of the InternalSession method now deletes all subscriptions in the subscription service (here) rather than only the ones specific to the session.

I went ahead and made a PR to fix this, and verified that my application worked as expected.
Would appreciate a review! #66

keepalive status?

@cbergmiller I am now looking at the asyncio stuff. and I now see that you completely remove the KeepAlive thread. Why? How do you then keep the secure session alive?

opcua-asyncio status

We need to write status somewhere (README?) so people are clear over current state. does the client work? does the server work? for what?

Client reconnect behaviour?

Hi,

We see a warning printed by our client, whenever our OPC UA server restarts.

[WARNING] asyncua.client.ua_client.UASocketProtocol - ServiceFault from server received in response to PublishRequest

Once this happens, the client's data change subscriptions no longer work.

Is there any particular configuration needed in code to make the client reconnect and resubscribe again? Can we get notifications from these ServiceFaults to deal with it ourselves?

Thanks for your feedback,
Dann

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.