Skip to content

Commit

Permalink
Add support for methods
Browse files Browse the repository at this point in the history
This patch adds support for the Method Service Set to call methods on
the server.

Fixes #251
  • Loading branch information
magiconair committed Aug 21, 2019
1 parent df55217 commit e53badd
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 9 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
vendor/
dist/
__pycache__/
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ The current set of supported services is only for the high-level client.
| | Write | Yes | |
| | HistoryRead | Yes | |
| | HistoryUpdate | | |
| Method Service Set | Call | | |
| Method Service Set | Call | Yes | |
| MonitoredItems Service Set | CreateMonitoredItems | Yes | |
| | DeleteMonitoredItems | Yes | |
| | ModifyMonitoredItems | | |
Expand Down
18 changes: 18 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,24 @@ func (c *Client) Browse(req *ua.BrowseRequest) (*ua.BrowseResponse, error) {
return res, err
}

// Call executes a synchronous call request for a single method.
func (c *Client) Call(req *ua.CallMethodRequest) (*ua.CallMethodResult, error) {
creq := &ua.CallRequest{
MethodsToCall: []*ua.CallMethodRequest{req},
}
var res *ua.CallResponse
err := c.Send(creq, func(v interface{}) error {
return safeAssign(v, &res)
})
if err != nil {
return nil, err
}
if len(res.Results) != 1 {
return nil, ua.StatusBadUnknownResponse
}
return res.Results[0], nil
}

// Subscribe creates a Subscription with given parameters. Parameters that have not been set
// (have zero values) are overwritten with default values.
// See opcua.DefaultSubscription* constants
Expand Down
49 changes: 49 additions & 0 deletions examples/method/method.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright 2018-2019 opcua authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package main

import (
"context"
"flag"
"log"

"github.com/gopcua/opcua"
"github.com/gopcua/opcua/debug"
"github.com/gopcua/opcua/ua"
)

func main() {
var (
endpoint = flag.String("endpoint", "opc.tcp://localhost:4840", "OPC UA Endpoint URL")
)
flag.BoolVar(&debug.Enable, "debug", false, "enable debug logging")
flag.Parse()
log.SetFlags(0)

ctx := context.Background()

c := opcua.NewClient(*endpoint, opcua.SecurityMode(ua.MessageSecurityModeNone))
if err := c.Connect(ctx); err != nil {
log.Fatal(err)
}
defer c.Close()

in := int64(12)
req := &ua.CallMethodRequest{
ObjectID: ua.NewStringNodeID(2, "main"),
MethodID: ua.NewStringNodeID(2, "even"),
InputArguments: []*ua.Variant{ua.MustVariant(in)},
}

resp, err := c.Call(req)
if err != nil {
log.Fatal(err)
}
if got, want := resp.StatusCode, ua.StatusOK; got != want {
log.Fatalf("got status %v want %v", got, want)
}
out := resp.OutputArguments[0].Value()
log.Printf("%d is even: %v", in, out)
}
25 changes: 25 additions & 0 deletions uatest/method_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env python3

from opcua import ua, Server

def even(parent, variant):
print("even method call with parameters: ", variant.Value)
ret = (variant.Value % 2 == 0)
print("even", type(ret))
return [ua.Variant(ret, ua.VariantType.Boolean)]

def square(parent, variant):
print("square method call with parameters: ", variant.Value)
variant.Value *= variant.Value
return [variant]

if __name__ == "__main__":
server = Server()
server.set_endpoint("opc.tcp://0.0.0.0:4840/")

ns = server.register_namespace("http://gopcua.com/")
main = server.nodes.objects.add_object(ua.NodeId("main", ns), "main")
fnEven = main.add_method(ua.NodeId("even", ns), "even", even, [ua.VariantType.Int64], [ua.VariantType.Boolean])
fnSquare = main.add_method(ua.NodeId("square", ns), "square", square, [ua.VariantType.Int64], [ua.VariantType.Int64])

server.start()
54 changes: 54 additions & 0 deletions uatest/method_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// +build integration

package uatest

import (
"context"
"testing"

"github.com/gopcua/opcua"
"github.com/gopcua/opcua/ua"
"github.com/pascaldekloe/goe/verify"
)

func TestCallMethod(t *testing.T) {
tests := []struct {
req *ua.CallMethodRequest
out []*ua.Variant
}{
{
req: &ua.CallMethodRequest{
ObjectID: ua.NewStringNodeID(2, "main"),
MethodID: ua.NewStringNodeID(2, "even"),
InputArguments: []*ua.Variant{
ua.MustVariant(int64(12)),
},
},
out: []*ua.Variant{ua.MustVariant(true)},
},
}

srv := NewServer("method_server.py")
defer srv.Close()

c := opcua.NewClient(srv.Endpoint, srv.Opts...)
if err := c.Connect(context.Background()); err != nil {
t.Fatal(err)
}
defer c.Close()

for _, tt := range tests {
t.Run(tt.req.ObjectID.String(), func(t *testing.T) {
resp, err := c.Call(tt.req)
if err != nil {
t.Fatal(err)
}
if got, want := resp.StatusCode, ua.StatusOK; got != want {
t.Fatalf("got status %v want %v", got, want)
}
if got, want := resp.OutputArguments, tt.out; !verify.Values(t, "", got, want) {
t.Fail()
}
})
}
}
10 changes: 2 additions & 8 deletions uatest/rw_server.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
#!/usr/bin/env python3

import logging
from opcua import ua, Server

if __name__ == "__main__":
logging.basicConfig(level=logging.WARN)

server = Server()
server.set_endpoint("opc.tcp://0.0.0.0:4840/gopcua/server/")
server.set_server_name("OPC/UA server Read/Write tests")

uri = "http://gopcua.com/"
ns = server.register_namespace(uri)
server.set_endpoint("opc.tcp://0.0.0.0:4840/")

ns = server.register_namespace("http://gopcua.com/")
main = server.nodes.objects.add_object(ua.NodeId("main", ns), "main")
roBool = main.add_variable(ua.NodeId("ro_bool", ns), "ro_bool", True, ua.VariantType.Boolean)
rwBool = main.add_variable(ua.NodeId("rw_bool", ns), "rw_bool", True, ua.VariantType.Boolean)
Expand Down

0 comments on commit e53badd

Please sign in to comment.