Beispiel #1
0
 def setUp(self):
     
     # create a new ClientSettings instance and add the localhost to the URLs to discover
     settings = ClientSettings()
     settings.discoveryUrls.append(ARGS.demo_url)
     settings.applicationName = "client"
     settings.logToStdOutLevel = ARGS.loglevel
     
     self.client = pyuaf.client.Client(settings)
 
     self.serverUri = ARGS.demo_server_uri
     demoNsUri = ARGS.demo_ns_uri
     plcOpenNsUri = "http://PLCopen.org/OpcUa/IEC61131-3/"
     
     # define some addresses
     self.addresses = [ Address(NodeId("Demo.SimulationSpeed", demoNsUri), self.serverUri),
                        Address(NodeId("Demo.SimulationActive", demoNsUri), self.serverUri) ]
     self.address_Method   = Address(ExpandedNodeId("Demo.Method", demoNsUri, self.serverUri))
     self.address_Multiply = Address(ExpandedNodeId("Demo.Method.Multiply", demoNsUri, self.serverUri))
     self.address_Alarms = Address(ExpandedNodeId("AlarmsWithNodes", demoNsUri, self.serverUri))
     
     readResult = self.client.read(self.addresses)
     self.values = [readResult.targets[0].data, readResult.targets[1].data]
     
     del self.client
     self.client = pyuaf.client.Client(settings)
    def setUp(self):
        
        # create a new ClientSettings instance and add the localhost to the URLs to discover
        settings = pyuaf.client.settings.ClientSettings()
        settings.discoveryUrls.append(ARGS.demo_url)
        settings.applicationName = "client"
        settings.logToStdOutLevel = ARGS.loglevel
    
        self.client = pyuaf.client.Client(settings)

        
        serverUri    = ARGS.demo_server_uri
        demoNsUri    = ARGS.demo_ns_uri
        plcOpenNsUri = "http://PLCopen.org/OpcUa/IEC61131-3/"
        
        
        self.address_Demo            = Address(ExpandedNodeId("Demo", demoNsUri, serverUri))
        self.address_StartSimulation = Address(self.address_Demo, [RelativePathElement(QualifiedName("StartSimulation", demoNsUri))])
        self.address_StopSimulation  = Address(self.address_Demo, [RelativePathElement(QualifiedName("StopSimulation", demoNsUri))])
        self.address_Scalar          = Address(self.address_Demo, [RelativePathElement(QualifiedName("Dynamic", demoNsUri)),
                                                                   RelativePathElement(QualifiedName("Scalar", demoNsUri))] )
        self.address_Byte            = Address(self.address_Scalar, [RelativePathElement(QualifiedName("Byte", demoNsUri))] )
        self.address_Int32           = Address(self.address_Scalar, [RelativePathElement(QualifiedName("Int32", demoNsUri))] )
        self.address_Int64           = Address(self.address_Scalar, [RelativePathElement(QualifiedName("Int64", demoNsUri))] )
        self.address_Float           = Address(self.address_Scalar, [RelativePathElement(QualifiedName("Float", demoNsUri))] )
        self.address_Double          = Address(self.address_Scalar, [RelativePathElement(QualifiedName("Double", demoNsUri))] )
        
        # start the simulation (otherwise the dynamic variables won't change)
        self.client.call(self.address_Demo, self.address_StartSimulation)
Beispiel #3
0
    def setUp(self):

        # create a new ClientSettings instance and add the localhost to the URLs to discover
        settings = pyuaf.client.settings.ClientSettings()
        settings.discoveryUrls.append(ARGS.demo_url)
        settings.applicationName = "client"
        settings.logToStdOutLevel = ARGS.loglevel

        self.client = pyuaf.client.Client(settings)

        serverUri = ARGS.demo_server_uri
        demoNsUri = ARGS.demo_ns_uri
        plcOpenNsUri = "http://PLCopen.org/OpcUa/IEC61131-3/"

        self.address_Scalar = Address(
            ExpandedNodeId("Demo.Static.Scalar", demoNsUri, serverUri))
        self.address_Byte = Address(
            self.address_Scalar,
            [RelativePathElement(QualifiedName("Byte", demoNsUri))])
        self.address_Int32 = Address(
            self.address_Scalar,
            [RelativePathElement(QualifiedName("Int32", demoNsUri))])
        self.address_Float = Address(
            self.address_Scalar,
            [RelativePathElement(QualifiedName("Float", demoNsUri))])
    def setUp(self):
        # create a new ClientSettings instance and add the localhost to the URLs to discover
        settings = pyuaf.client.settings.ClientSettings()
        settings.discoveryUrls.append(ARGS.demo_url)
        settings.applicationName = "client"
        settings.logToStdOutLevel = ARGS.loglevel

        self.client = MyClient(settings)

        serverUri = ARGS.demo_server_uri
        demoNsUri = ARGS.demo_ns_uri

        self.address_Demo = Address(
            ExpandedNodeId("Demo", demoNsUri, serverUri))
        self.address_Method = Address(
            self.address_Demo,
            [RelativePathElement(QualifiedName("Method", demoNsUri))])
        self.address_Multiply = Address(
            self.address_Method,
            [RelativePathElement(QualifiedName("Multiply", demoNsUri))])
        self.address_SetSimulationSpeed = Address(self.address_Demo, [
            RelativePathElement(QualifiedName("SetSimulationSpeed", demoNsUri))
        ])

        self.request = AsyncMethodCallRequest(1)
        self.request.targets[0].objectAddress = self.address_Method
        self.request.targets[0].methodAddress = self.address_Multiply
        self.request.targets[0].inputArguments.append(Double(2.0))
        self.request.targets[0].inputArguments.append(Double(3.0))
Beispiel #5
0
 def build_objects(self, address):
     o = Object(Node(self, address))
     browse_result = self.client.browse([address])
     for ri in xrange(len(browse_result.targets[0].references)):
         ref = browse_result.targets[0].references[ri]
         print ref.displayName
         # now we have information - node class
         if ref.nodeClass == nodeclasses.Variable:
             o.variables[str(ref.displayName.text())] = Variable(
                 Node(self, Address(ExpandedNodeId(ref.nodeId))))
         elif ref.nodeClass == nodeclasses.Method:
             o.methods[str(ref.displayName.text())] = Method(
                 Node(self, Address(ExpandedNodeId(ref.nodeId))), o)
         elif ref.nodeClass == nodeclasses.Object:
             o.children_objects[str(
                 ref.displayName.text())] = self.build_objects(
                     Address(ExpandedNodeId(ref.nodeId)))
     return o
Beispiel #6
0
    def setUp(self):
        
        # create a new ClientSettings instance and add the localhost to the URLs to discover
        settings = pyuaf.client.settings.ClientSettings()
        settings.discoveryUrls.append(ARGS.demo_url)
        settings.applicationName = "client"
        settings.logToStdOutLevel = ARGS.loglevel
    
        self.client = pyuaf.client.Client(settings)

        
        serverUri    = ARGS.demo_server_uri
        demoNsUri    = ARGS.demo_ns_uri
        plcOpenNsUri = "http://PLCopen.org/OpcUa/IEC61131-3/"
        
        self.address_Demo          = Address(ExpandedNodeId("Demo"               , demoNsUri, serverUri))
        self.address_StaticScalar  = Address(ExpandedNodeId("Demo.Static.Scalar" , demoNsUri, serverUri))
        self.address_DynamicScalar = Address(ExpandedNodeId("Demo.Dynamic.Scalar", demoNsUri, serverUri))
Beispiel #7
0
 def setUp(self):
     self.nsUri = "someNameSpaceUri"
 
     self.startingExpandedNodeId = ExpandedNodeId("someId", self.nsUri, "someServerUri")
 
     self.element0 = RelativePathElement(QualifiedName("element0", self.nsUri))
     self.element1 = RelativePathElement(QualifiedName("element1", self.nsUri))
     
     self.b0 = BrowsePath()
     self.b1 = BrowsePath(self.startingExpandedNodeId, [self.element0, self.element1])
Beispiel #8
0
    def setUp(self):

        # create a new ClientSettings instance and add the localhost to the URLs to discover
        settings = pyuaf.client.settings.ClientSettings()
        settings.discoveryUrls.append(ARGS.demo_url)
        settings.applicationName = "client"
        settings.logToStdOutLevel = ARGS.loglevel

        self.client = pyuaf.client.Client(settings)

        serverUri = ARGS.demo_server_uri
        demoNsUri = ARGS.demo_ns_uri
        plcOpenNsUri = "http://PLCopen.org/OpcUa/IEC61131-3/"

        # define some nodeids
        self.id0 = NodeId(opcuaidentifiers.OpcUaId_Server_Auditing, 0)
        self.id1 = NodeId(
            opcuaidentifiers.
            OpcUaId_Server_ServerCapabilities_MaxHistoryContinuationPoints, 0)
        self.id2 = NodeId("Demo.SimulationSpeed", 2)
        self.id3 = NodeId("Demo.SimulationActive", demoNsUri)
        self.id4 = NodeId(opcuaidentifiers.OpcUaId_Server_ServerArray, 0)

        # define some nodeids
        self.address0 = Address(ExpandedNodeId(self.id0, serverUri))
        self.address1 = Address(ExpandedNodeId(self.id1, serverUri))
        self.address2 = Address(ExpandedNodeId(self.id2, serverUri))
        self.address3 = Address(ExpandedNodeId(self.id3, serverUri))
        self.address4 = Address(ExpandedNodeId(self.id4, serverUri))

        # create some relative paths
        self.id5 = NodeId("Demo.BoilerDemo.Boiler1", demoNsUri)
        self.start5 = Address(ExpandedNodeId(self.id5, serverUri))
        self.name5 = QualifiedName("TemperatureSetPoint", demoNsUri)
        self.elem5 = RelativePathElement(self.name5)
        self.path5 = [self.elem5]
        self.address5 = Address(self.start5, self.path5)

        self.start6 = Address(ExpandedNodeId("Demo", demoNsUri, serverUri))
        self.elem6a = RelativePathElement(
            QualifiedName("BoilerDemo", demoNsUri))
        self.elem6b = RelativePathElement(QualifiedName("Boiler1", demoNsUri))
        self.path6 = [self.elem6a, self.elem6b]
        self.address6 = Address(self.start6, self.path6)

        self.elem7a = RelativePathElement(
            QualifiedName("TemperatureSensor", demoNsUri))
        self.elem7b = RelativePathElement(
            QualifiedName("Temperature", demoNsUri))
        self.path7 = [self.elem7a, self.elem7b]
        self.address7 = Address(self.address6, self.path7)
Beispiel #9
0
 def __init__(self,addr):
     self.a = addr
     self.contained = {}
     self.variables = {}
     #  execute browse
     browse_result = client.browse([ self.a ])
     for ri in xrange(len(browse_result.targets[0].references)):
         ref = browse_result.targets[0].references[ri]
         print ref.displayName
         # now we have information - node class
         if ref.nodeClass == nodeclasses.Variable:
             self.variables[str(ref.displayName.text())] = Address(ExpandedNodeId(ref.nodeId))
         elif ref.nodeClass == nodeclasses.Object:
             if unfold:
                 self.contained[str(ref.displayName.text())] = ObjectifiedNode( Address(ExpandedNodeId(ref.nodeId)) )
Beispiel #10
0
    def setUp(self):
        
        # create a new ClientSettings instance and add the localhost to the URLs to discover
        settings = pyuaf.client.settings.ClientSettings()
        settings.discoveryUrls.append(ARGS.demo_url)
        settings.applicationName = "client"
        settings.logToStdOutLevel = ARGS.loglevel
    
        self.client = pyuaf.client.Client(settings)

        
        serverUri    = ARGS.demo_server_uri
        demoNsUri    = ARGS.demo_ns_uri
        
        self.address_Demo     = Address(ExpandedNodeId("Demo", demoNsUri, serverUri))
        self.address_Method   = Address(self.address_Demo, [RelativePathElement(QualifiedName("Method", demoNsUri))] )
        self.address_Multiply = Address(self.address_Method, [RelativePathElement(QualifiedName("Multiply", demoNsUri))] )
        self.address_SetSimulationSpeed = Address(self.address_Demo, [RelativePathElement(QualifiedName("SetSimulationSpeed", demoNsUri))] )
Beispiel #11
0
 def setUp(self):
     
     # create a new ClientSettings instance and add the localhost to the URLs to discover
     settings = pyuaf.client.settings.ClientSettings()
     settings.discoveryUrls.append(ARGS.demo_url)
     settings.applicationName = "client"
     settings.logToStdOutLevel = ARGS.loglevel
     
     self.client = MyClient(settings)
 
     self.serverUri = ARGS.demo_server_uri
     demoNsUri = ARGS.demo_ns_uri
     plcOpenNsUri = "http://PLCopen.org/OpcUa/IEC61131-3/"
     
     # define some nodeids
     self.id = NodeId(opcuaidentifiers.OpcUaId_Server_Auditing, 0)
     
     # define some addresses
     self.address = Address(ExpandedNodeId(self.id, self.serverUri))
from pyuaf.client.settings       import ClientSettings
from pyuaf.client.requests       import TranslateBrowsePathsToNodeIdsRequest
from pyuaf.client.configs        import TranslateBrowsePathsToNodeIdsConfig
from pyuaf.util                  import Address, NodeId, RelativePathElement, QualifiedName, BrowsePath, ExpandedNodeId
from pyuaf.util                  import primitives
from pyuaf.util.errors           import UafError
from pyuaf.util.opcuaidentifiers import OpcUaId_RootFolder
from pyuaf.util.constants        import OPCUA_NAMESPACE_URI


# define the namespace URI and server URI of the UaDemoServer
demoNsUri     = "http://www.unifiedautomation.com/DemoServer"
demoServerUri = "urn:UnifiedAutomation:UaServerCpp"

# define a browse path to the HeaterStatus node
myStartingPoint = ExpandedNodeId( NodeId(OpcUaId_RootFolder, OPCUA_NAMESPACE_URI), demoServerUri )
myRelativePath  = [ RelativePathElement(QualifiedName("Objects"     , OPCUA_NAMESPACE_URI)),
                    RelativePathElement(QualifiedName("Demo"        , demoNsUri)),
                    RelativePathElement(QualifiedName("BoilerDemo"  , demoNsUri)),
                    RelativePathElement(QualifiedName("Boiler1"     , demoNsUri)),
                    RelativePathElement(QualifiedName("HeaterStatus", demoNsUri)) ]
myBrowsePath = BrowsePath(myStartingPoint, myRelativePath)

# define the ClientSettings:
settings = ClientSettings()
settings.applicationName = "MyClient"
settings.discoveryUrls.append("opc.tcp://localhost:48010")
# settings.logToStdOutLevel = pyuaf.util.loglevels.Debug # uncomment for seeing debugging information

# create the client
myClient = Client(settings)
Beispiel #13
0
    def setUp(self):

        # create a new ClientSettings instance and add the localhost to the URLs to discover
        settings = pyuaf.client.settings.ClientSettings()
        settings.discoveryUrls.append(ARGS.demo_url)
        settings.applicationName = "client"
        settings.logToStdOutLevel = ARGS.loglevel

        self.client = MyClient(settings)

        serverUri = ARGS.demo_server_uri
        demoNsUri = ARGS.demo_ns_uri
        opcUaNsIndex = 0  # the namespace index of nodes defined by the OPC UA specs is always 0

        self.address_Demo = Address(
            ExpandedNodeId("Demo", demoNsUri, serverUri))
        self.address_Events = Address(
            self.address_Demo,
            [RelativePathElement(QualifiedName("Events", demoNsUri))])
        self.address_Alarms = Address(
            self.address_Events,
            [RelativePathElement(QualifiedName("AlarmsWithNodes", demoNsUri))])
        self.address_Alarm = Address(self.address_Alarms, [
            RelativePathElement(QualifiedName("ExclusiveLevelAlarm",
                                              demoNsUri))
        ])
        self.address_Trigger = Address(self.address_Alarms, [
            RelativePathElement(
                QualifiedName("ExclusiveLevelAlarmTrigger", demoNsUri))
        ])
        self.address_LowLow = Address(
            self.address_Alarm,
            [RelativePathElement(QualifiedName("LowLowLimit", opcUaNsIndex))])
        self.address_Low = Address(
            self.address_Alarm,
            [RelativePathElement(QualifiedName("LowLimit", opcUaNsIndex))])
        self.address_High = Address(
            self.address_Alarm,
            [RelativePathElement(QualifiedName("HighLimit", opcUaNsIndex))])
        self.address_HighHigh = Address(self.address_Alarm, [
            RelativePathElement(QualifiedName("HighHighLimit", opcUaNsIndex))
        ])

        # start the simulation (otherwise the dynamic variables won't change)
        res = self.client.read([
            self.address_LowLow, self.address_Low, self.address_High,
            self.address_HighHigh
        ])

        self.assertTrue(res.overallStatus.isGood())

        self.lowLowLimit = res.targets[0].data.value
        self.lowLimit = res.targets[1].data.value
        self.highLimit = res.targets[2].data.value
        self.highHighLimit = res.targets[3].data.value

        self.eventFilter = EventFilter()
        self.eventFilter.selectClauses.resize(3)
        self.eventFilter.selectClauses[0].attributeId = attributeids.Value
        self.eventFilter.selectClauses[0].browsePath.append(
            QualifiedName("Message", 0))
        self.eventFilter.selectClauses[0].typeId = NodeId(
            opcuaidentifiers.OpcUaId_BaseEventType, 0)
        self.eventFilter.selectClauses[1].attributeId = attributeids.Value
        self.eventFilter.selectClauses[1].browsePath.append(
            QualifiedName("SourceName", 0))
        self.eventFilter.selectClauses[1].typeId = NodeId(
            opcuaidentifiers.OpcUaId_BaseEventType, 0)
        self.eventFilter.selectClauses[2].attributeId = attributeids.Value
        self.eventFilter.selectClauses[2].browsePath.append(
            QualifiedName("Severity", 0))
        self.eventFilter.selectClauses[2].typeId = NodeId(
            opcuaidentifiers.OpcUaId_BaseEventType, 0)

        # make sure the trigger has a default value
        result = self.client.write([self.address_Trigger], [Double(50.0)])
        # Check if the write failed due to a BadUserAccessDenied failure
        # This appears to be the case for the UaServerCpp shipped with the Windows MSVS2008 demo SDK,
        # probably a bug in the UaServerCpp.
        if result.targets[0].status.opcUaStatusCode(
        ) == pyuaf.util.opcuastatuscodes.OpcUa_BadUserAccessDenied:
            self.skipTest(
                "Some old versions of the UaServerCpp have non-writeable triggers (bug in UaServerCpp?)"
            )
Beispiel #14
0
Root_NodeId = NodeId(OpcUaId_RootFolder, OPCUA_NAMESPACE_URI,
                     OPCUA_NAMESPACE_ID)  # redundant namespace info, but valid

# NodeIds don't contain info about the server they are hosted by.
# If you specifically want to refer to a NodeId within a particular server, you need to
# use an ExpandedNodeId, which contains
#   - a NodeId
#   - and a serverUri
# Assume from now on that the particular nodes we want to refer to, are hosted by a server defined
# by the server URI "urn:UnifiedAutomation:UaDemoserver":
serverUri = "urn:UnifiedAutomation:UaDemoserver"
# Then we can refer to the Root node like this:
Root_Node = Address(Root_NodeId, serverUri)
# An absolute address can also be created directly from an ExpandedNodeId:
Root_Node = Address(
    ExpandedNodeId(OpcUaId_RootFolder, OPCUA_NAMESPACE_ID, serverUri))

# within the Root folder, there is another standard node called the Objects folder:
Objects_Node = Address(NodeId(OpcUaId_ObjectsFolder, OPCUA_NAMESPACE_ID),
                       serverUri)

# we could also refer to the Objects node via a relative path!
# We can do this, since the standard Object node has a standard BrowseName.
# The following are all valid ways to define the BrowseName of the Objects node
Objects_BrowseName = QualifiedName("Objects", OPCUA_NAMESPACE_ID)
Objects_BrowseName = QualifiedName(
    "Objects", OPCUA_NAMESPACE_URI)  # namespace URI instead of index
Objects_BrowseName = QualifiedName(
    "Objects", OPCUA_NAMESPACE_URI,
    OPCUA_NAMESPACE_ID)  # redundant namespace info, but valid
# we can now create a path from the Root node to the Objects node, using a path of one element:
print(
    "################################################################################################################"
)
print("")

# There are *many* ways how you can identify (address) a node, see the examples below:
# 1) absolute address to the standard OPC UA "RootFolder" node (notice the standard OPC UA index 0)
# 2) absolute address to the non-standard "Demo" node (notice the demo server namespace URI)
# 3) absolute address to the non-standard "BoilerDemo" node (notice that we use an ExpandedNodeId this time)
# 4) relative address to the "Boiler1" node (relative to the previous address)
# 5) relative address to the "TemperatureSetpoint" Double variable (relative to the previous relative (!!!) address)
# 6) relative address to the "HeaterStatus" node (relative to the standard "Root" folder)
address_Root = Address(NodeId(OpcUaId_RootFolder, 0), demoServerUri)
address_Demo = Address(NodeId("Demo", demoNsUri), demoServerUri)
address_BoilerDemo = Address(
    ExpandedNodeId("Demo.BoilerDemo", demoNsUri, demoServerUri))
address_Boiler1 = Address(
    address_BoilerDemo,
    [RelativePathElement(QualifiedName("Boiler1", demoNsUri))])
address_TSetpoint = Address(
    address_Boiler1,
    [RelativePathElement(QualifiedName("TemperatureSetPoint", demoNsUri))])
address_HeaterStatus = Address(address_Root, [
    RelativePathElement(QualifiedName("Objects", 0)),
    RelativePathElement(QualifiedName("Demo", demoNsUri)),
    RelativePathElement(QualifiedName("BoilerDemo", demoNsUri)),
    RelativePathElement(QualifiedName("Boiler1", demoNsUri)),
    RelativePathElement(QualifiedName("HeaterStatus", demoNsUri))
])

# In the above examples, 0 is used to identify the "standard OPC UA namespace" (which is ALWAYS 0).
print("################################################################################################################")
print("Step 3: Specify the addresses to some nodes which we would like to read/write/browse/monitor/call/...")
print("################################################################################################################")
print("")


# There are *many* ways how you can identify (address) a node, see the examples below:
# 1) absolute address to the standard OPC UA "RootFolder" node (notice the standard OPC UA index 0)
# 2) absolute address to the non-standard "Demo" node (notice the demo server namespace URI)
# 3) absolute address to the non-standard "BoilerDemo" node (notice that we use an ExpandedNodeId this time)
# 4) relative address to the "Boiler1" node (relative to the previous address)
# 5) relative address to the "TemperatureSetpoint" Double variable (relative to the previous relative (!!!) address)
# 6) relative address to the "HeaterStatus" node (relative to the standard "Root" folder)
address_Root         = Address( NodeId(OpcUaId_RootFolder , 0        ), demoServerUri )
address_Demo         = Address( NodeId("Demo"             , demoNsUri), demoServerUri )
address_BoilerDemo   = Address( ExpandedNodeId("Demo.BoilerDemo", demoNsUri, demoServerUri) )
address_Boiler1      = Address( address_BoilerDemo , [ RelativePathElement(QualifiedName("Boiler1"            , demoNsUri)) ] )
address_TSetpoint    = Address( address_Boiler1    , [ RelativePathElement(QualifiedName("TemperatureSetPoint", demoNsUri)) ] )
address_HeaterStatus = Address( address_Root       , [ RelativePathElement(QualifiedName("Objects"            , 0        )),
                                                       RelativePathElement(QualifiedName("Demo"               , demoNsUri)),
                                                       RelativePathElement(QualifiedName("BoilerDemo"         , demoNsUri)),
                                                       RelativePathElement(QualifiedName("Boiler1"            , demoNsUri)),
                                                       RelativePathElement(QualifiedName("HeaterStatus"       , demoNsUri)) ] )


# In the above examples, 0 is used to identify the "standard OPC UA namespace" (which is ALWAYS 0).
# We could also have replaced 0 with the standard OPC UA namespace URI ('http://opcfoundation.org/UA/').
# This namespace URI is available as a constant: pyuaf.util.constants.OPCUA_NAMESPACE_URI.

# As you can see above, there are a variety of ways how you can address a node. 
# But there are even more things you can do:
Beispiel #17
0
def main_recurse(client, server_uri, document):
    context = new_context()
    starting_address = ExpandedNodeId(opcuaidentifiers.OpcUaId_ObjectsFolder,
                                      constants.OPCUA_NAMESPACE_ID, server_uri)
    recurse(client, starting_address, document, None, None, context)
    print 'Error counter: ' + str(context['errors'])
Beispiel #18
0
 def test_util_BrowsePath_startingExpandedNodeId(self):
     self.assertEqual( self.b0.startingExpandedNodeId , ExpandedNodeId() )
     self.assertEqual( self.b1.startingExpandedNodeId , self.startingExpandedNodeId )