Skip to content

Commit

Permalink
Merge pull request #258 from gopcua/methods
Browse files Browse the repository at this point in the history
Add support for methods
  • Loading branch information
magiconair authored Aug 21, 2019
2 parents df55217 + e53badd commit 553a90f
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 553a90f

Please sign in to comment.