FreeOpcUa / opcua-asyncio

OPC UA library for python >= 3.7
GNU Lesser General Public License v3.0
1.12k stars 361 forks source link

Error with subscription datachange #257

Closed sth05 closed 4 years ago

sth05 commented 4 years ago

Pardon my ignorance, I am new to both Python and OPC UA, but I believe I have found a bug in the subscription module in either the SubHandler sample class or the _call_datachange method of Subscription.

class SubHandler:
    def datachange_notification(self, node, val, data):
        print("datachange_notification: NODE:%r VALUE:%s" % (node, val))

I will take line 128 from subscription.py (At the time of writing, not sure if there's a way to link it) as an example, but it seems that all of _call_datachange would be affected:

 self._handler.datachange_notification(data.node, item.Value.Value.Value, event_data)

Seems to only have 3 parameters, which produces the error below. If I delete the self parameter from SubHandler.datachange_notification or add self to the method it works fine.

ERROR:asyncua.common.subscription:Exception calling data change handler
Traceback (most recent call last):
  File "C:\Users\Hermann\AppData\Local\Programs\Python\Python38-32\lib\site-packages\asyncua\common\subscription.py", line 128, in _call_datachange
    self._handler.datachange_notification(data.node, item.Value.Value.Value, event_data)
TypeError: datachange_notification() missing 1 required positional argument: 'data'
AndreasHeine commented 4 years ago

which version did you use? when did the error happen?

i am using asyncua-0.8.4 and everything works fine !?

edit: this is my subhandler i tested with

class SubscriptionHandler:
    """
    The SubscriptionHandler is used to handle the data that is received for the subscription.
    """
    def datachange_notification(self, node: Node, val, data):
        """
        Callback for asyncua Subscription.
        This method will be called when the Client received a data change message from the Server.
        """
        datachange_notification_queue.append((node, val, data))
sth05 commented 4 years ago

asyncua 0.8.4. Python 3.8

I just made a new Pycharm project and made it with their virtual environment to test it on a clean install and the error is still there.

Here is my SubHandler and subscription code:

import asyncio
import logging
from asyncua import Client, Node, ua
#import asyncua.common.ua_utils as ua_utils

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

class SubHandler:

    def datachange_notification(self, node: Node, val, data):
        print("datachange_notification: NODE:%r VALUE:%s" % (node, val))
        #_logger.info('datachange_notification %r %s',  val, node)

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

async def main():
    url = "opc.tcp://localhost:4840"
    async with Client(url=url) as client:

        uri = "HTL-DA"
        idx = await client.get_namespace_index(uri)

        # Subscription that requests data changes from node DA\Auto
        handler = SubHandler
        auto_node = await client.nodes.objects.get_child([f"{idx}:DA", f"{idx}:Auto", f"{idx}:MyVariable"])
        subscription = await client.create_subscription(500,handler)
        nodes = [
            auto_node,
            client.get_node(ua.ObjectIds.Server_ServerStatus_CurrentTime),
        ]
        sub_return = await subscription.subscribe_data_change(nodes)

        while True:
            await asyncio.sleep(10)

if __name__ == "__main__":
    asyncio.run(main())

Here is my full code just in case:

`import asyncio
import logging
from asyncua import Client, Node, ua
#import asyncua.common.ua_utils as ua_utils

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

class SubHandler:

    def datachange_notification(self, node: Node, val, data):
        print("datachange_notification: NODE:%r VALUE:%s" % (node, val))
        #_logger.info('datachange_notification %r %s',  val, node)

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

async def main():
    url = "opc.tcp://localhost:4840"
    async with Client(url=url) as client:
        _logger.info("Root node is: %r", client.nodes.root)
        _logger.info("Objects node is: %r", client.nodes.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 client.nodes.root.get_children())

        uri = "HTL-DA"
        idx = await client.get_namespace_index(uri)
        _logger.info("index of our namespace is %s", idx)

        dataRoot = await client.nodes.objects.get_child(f"{idx}:DA")
        dataChildren = await dataRoot.get_children()

        #Print children name and value of DA
        for node in dataChildren:
            node_name = await node.read_display_name()
            print(f'NAME:{node_name.Text} ID:{node}')

            child = await node.get_children()
            for sensor in child:
                sensor_name = await sensor.read_display_name()
                print(f'\tNAME:{sensor_name.Text}\n\t\tID:{sensor}\n\t\tVALUE:{await sensor.read_value()}')

        # Subscription that requests data changes from node DA\Auto
        handler = SubHandler
        auto_node = await client.nodes.objects.get_child([f"{idx}:DA", f"{idx}:Auto", f"{idx}:MyVariable"])
        subscription = await client.create_subscription(500,handler)
        nodes = [
            auto_node,
            client.get_node(ua.ObjectIds.Server_ServerStatus_CurrentTime),
        ]
        sub_return = await subscription.subscribe_data_change(nodes)

        while True:
            await asyncio.sleep(1)

if __name__ == "__main__":
    asyncio.run(main())
AndreasHeine commented 4 years ago

@HermannSt you are missing "()" after SubHandler ;)

handler = SubHandler()

handler = SubscriptionHandler()
handler1 = SubscriptionHandler

print(handler)
print(handler1)

<main.SubscriptionHandler object at 0x0000021DFA0A06D8> <class 'main.SubscriptionHandler'>

without "()" your just reference the class and did not get a instance of it!

sth05 commented 4 years ago

haha...^^ well, thanks a lot, I really appreciated your help