Commit 92999182 authored by ORD's avatar ORD

Merge pull request #179 from FreeOpcUa/evfilter

WhereClause support
parents 94ecade8 8b3323a7
......@@ -23,9 +23,9 @@ class SubHandler(object):
if __name__ == "__main__":
#from IPython import embed
logging.basicConfig(level=logging.DEBUG)
#client = Client("opc.tcp://localhost:53530/OPCUA/SimulationServer/")
client = Client("opc.tcp://olivier:olivierpass@localhost:53530/OPCUA/SimulationServer/")
client.set_security_string("Basic256,SignAndEncrypt,certificate-example.der,private-key-example.pem")
client = Client("opc.tcp://localhost:53530/OPCUA/SimulationServer/")
#client = Client("opc.tcp://olivier:olivierpass@localhost:53530/OPCUA/SimulationServer/")
#client.set_security_string("Basic256,SignAndEncrypt,certificate-example.der,private-key-example.pem")
try:
client.connect()
root = client.get_root_node()
......
import sys
sys.path.insert(0, "..")
import logging
from opcua import Client
from opcua import ua
from IPython import embed
class SubHandler(object):
"""
Subscription Handler. To receive events from server for a subscription
"""
def datachange_notification(self, node, val, data):
print("Python: New data change event", node, val)
def event_notification(self, event):
print("Python: New event", event.EventType)
if __name__ == "__main__":
#from IPython import embed
logging.basicConfig(level=logging.WARN)
client = Client("opc.tcp://localhost:53530/OPCUA/SimulationServer/")
#client = Client("opc.tcp://olivier:olivierpass@localhost:53530/OPCUA/SimulationServer/")
try:
client.connect()
root = client.get_root_node()
print("Root is", root)
handler = SubHandler()
sub = client.create_subscription(500, handler)
handle = sub.subscribe_events(evtype=2788)
# refresh server condition to force generation of events
cond = root.get_child(["0:Types", "0:EventTypes", "0:BaseEventType", "0:ConditionType"])
cond.call_method("0:ConditionRefresh", ua.Variant(sub.subscription_id, ua.VariantType.UInt32))
embed()
finally:
client.disconnect()
......@@ -53,10 +53,12 @@ if __name__ == "__main__":
try:
# time.sleep is here just because we want to see events in UaExpert
import time
for i in range(1, 10):
time.sleep(10)
myevgen.trigger(message="This is MyFirstEvent with MyNumericProperty and MyStringProperty.")
mysecondevgen.trigger(message="This is MySecondEvent with MyIntProperty and MyBoolProperty.")
count = 0
while True:
time.sleep(2)
myevgen.trigger(message="MyFirstEvent " + str(count))
mysecondevgen.trigger(message="MySecondEvent " + str(count))
count += 1
embed()
finally:
......
......@@ -211,22 +211,56 @@ class Subscription(object):
def _get_filter_from_event_type(self, eventtype):
eventtype = self._get_node(eventtype)
evfilter = ua.EventFilter()
for property in get_event_properties_from_type_node(eventtype):
op = ua.SimpleAttributeOperand()
op.TypeDefinitionId = eventtype.nodeid
op.AttributeId = ua.AttributeIds.Value
op.BrowsePath = [property.get_browse_name()]
evfilter.SelectClauses.append(op)
evfilter.SelectClauses = self._select_clauses_from_evtype(eventtype)
evfilter.WhereClause = self._where_clause_from_evtype(eventtype)
return evfilter
def subscribe_events(self, sourcenode=ua.ObjectIds.Server, evtype=ua.ObjectIds.BaseEventType):
def _select_clauses_from_evtype(self, evtype):
clauses = []
for prop in get_event_properties_from_type_node(evtype):
op = ua.SimpleAttributeOperand()
op.TypeDefinitionId = evtype.nodeid
op.AttributeId = ua.AttributeIds.Value
op.BrowsePath = [prop.get_browse_name()]
clauses.append(op)
return clauses
def _where_clause_from_evtype(self, evtype):
cf = ua.ContentFilter()
el = ua.ContentFilterElement()
# operands can be ElementOperand, LiteralOperand, AttributeOperand, SimpleAttribute
op = ua.SimpleAttributeOperand()
op.TypeDefinitionId = evtype.nodeid
op.BrowsePath.append(ua.QualifiedName("EventType", 0))
op.AttributeId = ua.AttributeIds.Value
el.FilterOperands.append(op)
for subtypeid in [st.nodeid for st in self._get_subtypes(evtype)]:
op = ua.LiteralOperand()
op.Value = ua.Variant(subtypeid)
el.FilterOperands.append(op)
el.FilterOperator = ua.FilterOperator.InList
cf.Elements.append(el)
return cf
def _get_subtypes(self, parent, nodes=None):
if nodes is None:
nodes = [parent]
for child in parent.get_children(refs=ua.ObjectIds.HasSubtype):
nodes.append(child)
self._get_subtypes(child, nodes)
return nodes
def subscribe_events(self, sourcenode=ua.ObjectIds.Server, evtype=ua.ObjectIds.BaseEventType, evfilter=None):
"""
Subscribe to events from a node. Default node is Server node.
In most servers the server node is the only one you can subscribe to.
if evfilter is provided, evtype is ignored
Return a handle which can be used to unsubscribe
"""
sourcenode = self._get_node(sourcenode)
evfilter = self._get_filter_from_event_type(evtype)
if evfilter is None:
evfilter = self._get_filter_from_event_type(evtype)
return self._subscribe(sourcenode, ua.AttributeIds.EventNotifier, evfilter)
def _subscribe(self, nodes, attr, mfilter=None, queuesize=0):
......
......@@ -56,7 +56,7 @@ class EventGenerator(object):
source = Node(self.isession, self.event.SourceNode)
self.event.SourceNode = source.nodeid
self.event.SourceName = source.get_display_name().Text
self.event.SourceName = source.get_browse_name().Name
source.set_attribute(ua.AttributeIds.EventNotifier, ua.DataValue(ua.Variant(1, ua.VariantType.Byte)))
refs = []
......
This diff is collapsed.
......@@ -4,12 +4,13 @@ from opcua import Client
from opcua import Server
from opcua import ua
from tests_subscriptions import SubscriptionTests
from tests_common import CommonTests, add_server_methods
port_num1 = 48510
class TestClient(unittest.TestCase, CommonTests):
class TestClient(unittest.TestCase, CommonTests, SubscriptionTests):
'''
Run common tests on client side
......
This diff is collapsed.
import unittest
from tests_common import CommonTests, add_server_methods, MySubHandler
import os
import shelve
import time
from tests_common import CommonTests, add_server_methods
from tests_subscriptions import SubscriptionTests
from datetime import timedelta, datetime
from tempfile import NamedTemporaryFile
......@@ -17,7 +19,7 @@ port_num = 485140
port_discovery = 48550
class TestServer(unittest.TestCase, CommonTests):
class TestServer(unittest.TestCase, CommonTests, SubscriptionTests):
'''
Run common tests on server side
......@@ -327,7 +329,7 @@ class TestServer(unittest.TestCase, CommonTests):
def check_eventgenerator_SourceServer(test, evgen):
server = test.opc.get_server_node()
test.assertEqual(evgen.event.SourceName, server.get_display_name().Text)
test.assertEqual(evgen.event.SourceName, server.get_browse_name().Name)
test.assertEqual(evgen.event.SourceNode, ua.NodeId(ua.ObjectIds.Server))
test.assertEqual(server.get_attribute(ua.AttributeIds.EventNotifier).Value, ua.Variant(1, ua.VariantType.Byte))
refs = server.get_referenced_nodes(ua.ObjectIds.GeneratesEvent, ua.BrowseDirection.Forward, ua.NodeClass.ObjectType, False)
......@@ -335,7 +337,7 @@ def check_eventgenerator_SourceServer(test, evgen):
def check_event_generator_object(test, evgen, obj):
test.assertEqual(evgen.event.SourceName, obj.get_display_name().Text)
test.assertEqual(evgen.event.SourceName, obj.get_browse_name().Name)
test.assertEqual(evgen.event.SourceNode, obj.nodeid)
test.assertEqual(obj.get_attribute(ua.AttributeIds.EventNotifier).Value, ua.Variant(1, ua.VariantType.Byte))
refs = obj.get_referenced_nodes(ua.ObjectIds.GeneratesEvent, ua.BrowseDirection.Forward, ua.NodeClass.ObjectType, False)
......
This diff is collapsed.
......@@ -9,6 +9,7 @@ from opcua import ua
from opcua.ua import extensionobject_from_binary
from opcua.ua import extensionobject_to_binary
from opcua.ua.uatypes import flatten, get_shape, reshape
from opcua.server.internal_subscription import WhereClauseEvaluator
......@@ -358,7 +359,31 @@ class TestUnit(unittest.TestCase):
n = ua.NodeId(0, 3)
self.assertFalse(n.is_null())
self.assertTrue(n.has_null_identifier())
def test_where_clause(self):
cf = ua.ContentFilter()
el = ua.ContentFilterElement()
op = ua.SimpleAttributeOperand()
op.BrowsePath.append(ua.QualifiedName("property", 2))
el.FilterOperands.append(op)
for i in range(10):
op = ua.LiteralOperand()
op.Value = ua.Variant(i)
el.FilterOperands.append(op)
el.FilterOperator = ua.FilterOperator.InList
cf.Elements.append(el)
wce = WhereClauseEvaluator(logging.getLogger(__name__), None, cf)
ev = ua.BaseEvent()
ev._freeze = False
ev.property = 3
self.assertTrue(wce.eval(ev))
if __name__ == '__main__':
logging.basicConfig(level=logging.WARN)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment