越来越坏MonitoredItemFilterUnsupported (0x80440000)
Getting BadMonitoredItemFilterUnsupported (0x80440000)
我正在使用 GOPCUA v0.2.0-rc2 库连接到 OPC UA 服务器。如果我不在监控项中使用任何过滤器,一切正常。但我想使用 datachange 过滤器,以便仅当它们按一定百分比或绝对值变化时才能够接收值。以下是完整代码。
package main
import (
"context"
"flag"
"fmt"
"log"
"time"
"github.com/gopcua/opcua"
"github.com/gopcua/opcua/debug"
"github.com/gopcua/opcua/ua"
)
func main() {
var (
endpoint = flag.String("endpoint", "opc.tcp://192.168.189.1:49320", "OPC UA Endpoint URL")
policy = flag.String("policy", "None", "Security policy: None, Basic128Rsa15, Basic256, Basic256Sha256. Default: None")
mode = flag.String("mode", "None", "Security mode: None, Sign, SignAndEncrypt. Default: None")
certFile = flag.String("cert", "", "Path to cert.pem. Required for security mode/policy != None")
keyFile = flag.String("key", "", "Path to private key.pem. Required for security mode/policy != None")
nodeID = flag.String("node", "ns=2;s=HONDA.DEV1.T1", "node id to subscribe to")
interval = flag.String("interval", opcua.DefaultSubscriptionInterval.String(), "subscription interval")
)
flag.BoolVar(&debug.Enable, "debug", false, "enable debug logging")
flag.Parse()
log.SetFlags(0)
subInterval, err := time.ParseDuration(*interval)
if err != nil {
log.Fatal(err)
}
// add an arbitrary timeout to demonstrate how to stop a subscription
// with a context.
d := 10 * time.Second
ctx, cancel := context.WithTimeout(context.Background(), d)
defer cancel()
endpoints, err := opcua.GetEndpoints(ctx, *endpoint)
if err != nil {
log.Fatal(err)
}
ep := opcua.SelectEndpoint(endpoints, *policy, ua.MessageSecurityModeFromString(*mode))
if ep == nil {
log.Fatal("Failed to find suitable endpoint")
}
fmt.Println("*", ep.SecurityPolicyURI, ep.SecurityMode)
opts := []opcua.Option{
opcua.SecurityPolicy(*policy),
opcua.SecurityModeString(*mode),
opcua.CertificateFile(*certFile),
opcua.PrivateKeyFile(*keyFile),
opcua.AuthAnonymous(),
opcua.SecurityFromEndpoint(ep, ua.UserTokenTypeAnonymous),
}
c := opcua.NewClient(ep.EndpointURL, opts...)
if err := c.Connect(ctx); err != nil {
log.Fatal(err)
}
defer c.Close()
notifyCh := make(chan *opcua.PublishNotificationData)
sub, err := c.Subscribe(&opcua.SubscriptionParameters{
Interval: subInterval,
}, notifyCh)
if err != nil {
log.Fatal(err)
}
defer sub.Cancel()
log.Printf("Created subscription with id %v", sub.SubscriptionID)
id, err := ua.ParseNodeID(*nodeID)
if err != nil {
log.Fatal(err)
}
var miCreateRequest *ua.MonitoredItemCreateRequest
var eventFieldNames []string
miCreateRequest = valueRequest(id)
res, err := sub.Monitor(ua.TimestampsToReturnBoth, miCreateRequest)
if err != nil || res.Results[0].StatusCode != ua.StatusOK {
log.Fatal(err)
}
// read from subscription's notification channel until ctx is cancelled
for {
select {
case <-ctx.Done():
return
case res := <-notifyCh:
if res.Error != nil {
log.Print(res.Error)
continue
}
switch x := res.Value.(type) {
case *ua.DataChangeNotification:
for _, item := range x.MonitoredItems {
data := item.Value.Value.Value()
log.Printf("MonitoredItem with client handle %v = %v", item.ClientHandle, data)
}
case *ua.EventNotificationList:
for _, item := range x.Events {
log.Printf("Event for client handle: %v\n", item.ClientHandle)
for i, field := range item.EventFields {
log.Printf("%v: %v of Type: %T", eventFieldNames[i], field.Value(), field.Value())
}
log.Println()
}
default:
log.Printf("what's this publish result? %T", res.Value)
}
}
}
}
func valueRequest(nodeID *ua.NodeID) *ua.MonitoredItemCreateRequest {
handle := uint32(42)
attributeID := ua.AttributeIDValue
filter := ua.DataChangeFilter{}
filter.Trigger = ua.DataChangeTriggerStatusValue
filter.DeadbandType = uint32(ua.DeadbandTypeNone)
filter.DeadbandValue = 0.0
filterExtObj := ua.ExtensionObject{
EncodingMask: ua.ExtensionObjectBinary,
TypeID: &ua.ExpandedNodeID{
NodeID: nodeID,
},
Value: filter,
}
request := &ua.MonitoredItemCreateRequest{
ItemToMonitor: &ua.ReadValueID{
NodeID: nodeID,
AttributeID: attributeID,
DataEncoding: &ua.QualifiedName{},
},
MonitoringMode: ua.MonitoringModeReporting,
RequestedParameters: &ua.MonitoringParameters{
ClientHandle: handle,
DiscardOldest: true,
Filter: &filterExtObj,
QueueSize: 10,
SamplingInterval: 0.0,
},
}
return request
}
发送监控请求时,出现如下错误。
The server does not support the requested monitored item filter. StatusBadMonitoredItemFilterUnsupported (0x80440000)
服务器为Kepware OPC UA服务器,服务器端日志如下,
服务器收到请求
4/15/2021 5:24:07.474 PM [gopcua-1618489446170158449] CreateMonitoredItemsRequest
0000000000: Event started
0000000000: Request Header:
0000000000: authenticationToken: i=2991937600
0000000000: timestamp (UTC): 2021-04-15T12:24:06.180
0000000000: requestHandle: 5
0000000000: returnDiagnostics: 0
0000000000: auditEntryId: [empty]
0000000000: timeoutHint(ms): 10000
0000000000: Parameters:
0000000000: subscriptionId: 16
0000000000: timestampsToReturn: Both
0000000000: monitoredItemCreateRequests []: Size: 1
0000000000: monitoredItemCreateRequests [ 0 ]:
0000000000: itemToMonitor:
0000000000: nodeId: ns=2;s=HONDA.DEV1.T1
0000000000: attributeId: Value
0000000000: indexRange: [empty]
0000000000: dataEncoding: [empty]
0000000000: monitoringMode: Reporting
0000000000: requestedParameters:
0000000000: clientHandle: 42
0000000000: samplingInterval: 0
0000000000: filter:
0000000000: parameterTypeId: 67800040
0000000000: queueSize: 10
0000000000: discardOldest: 1
0000000000: Event complete
服务器发送的响应。
4/15/2021 5:24:07.474 PM [gopcua-1618489446170158449] CreateMonitoredItemsResponse
0000000000: Event started
0000000000: Response Header:
0000000000: timestamp (UTC): 2021-04-15T12:24:07.474
0000000000: requestHandle: 5
0000000000: serviceResult: 0x00000000 (Good)
0000000000: Parameters:
0000000000: monitoredItemCreateResults []: Size: 1
0000000000: monitoredItemCreateResults [ 0 ]:
0000000000: statusCode: 0x80440000 (BadMonitoredItemFilterUnsupported)
0000000000: monitoredItemId: 0
0000000000: revisedSamplingInterval: 0
0000000000: revisedQueueSize: 0
0000000000: filterResult: [empty]
0000000000: Event complete
在我看来,您正在尝试使用您正在为其创建 MonitoredItem 的节点的 NodeId 来构建包含您的过滤器结构的 ExtensionObject,而不是标识您的过滤器结构的 DataTypeEncoding 的 NodeId'正在使用。
我正在使用 GOPCUA v0.2.0-rc2 库连接到 OPC UA 服务器。如果我不在监控项中使用任何过滤器,一切正常。但我想使用 datachange 过滤器,以便仅当它们按一定百分比或绝对值变化时才能够接收值。以下是完整代码。
package main
import (
"context"
"flag"
"fmt"
"log"
"time"
"github.com/gopcua/opcua"
"github.com/gopcua/opcua/debug"
"github.com/gopcua/opcua/ua"
)
func main() {
var (
endpoint = flag.String("endpoint", "opc.tcp://192.168.189.1:49320", "OPC UA Endpoint URL")
policy = flag.String("policy", "None", "Security policy: None, Basic128Rsa15, Basic256, Basic256Sha256. Default: None")
mode = flag.String("mode", "None", "Security mode: None, Sign, SignAndEncrypt. Default: None")
certFile = flag.String("cert", "", "Path to cert.pem. Required for security mode/policy != None")
keyFile = flag.String("key", "", "Path to private key.pem. Required for security mode/policy != None")
nodeID = flag.String("node", "ns=2;s=HONDA.DEV1.T1", "node id to subscribe to")
interval = flag.String("interval", opcua.DefaultSubscriptionInterval.String(), "subscription interval")
)
flag.BoolVar(&debug.Enable, "debug", false, "enable debug logging")
flag.Parse()
log.SetFlags(0)
subInterval, err := time.ParseDuration(*interval)
if err != nil {
log.Fatal(err)
}
// add an arbitrary timeout to demonstrate how to stop a subscription
// with a context.
d := 10 * time.Second
ctx, cancel := context.WithTimeout(context.Background(), d)
defer cancel()
endpoints, err := opcua.GetEndpoints(ctx, *endpoint)
if err != nil {
log.Fatal(err)
}
ep := opcua.SelectEndpoint(endpoints, *policy, ua.MessageSecurityModeFromString(*mode))
if ep == nil {
log.Fatal("Failed to find suitable endpoint")
}
fmt.Println("*", ep.SecurityPolicyURI, ep.SecurityMode)
opts := []opcua.Option{
opcua.SecurityPolicy(*policy),
opcua.SecurityModeString(*mode),
opcua.CertificateFile(*certFile),
opcua.PrivateKeyFile(*keyFile),
opcua.AuthAnonymous(),
opcua.SecurityFromEndpoint(ep, ua.UserTokenTypeAnonymous),
}
c := opcua.NewClient(ep.EndpointURL, opts...)
if err := c.Connect(ctx); err != nil {
log.Fatal(err)
}
defer c.Close()
notifyCh := make(chan *opcua.PublishNotificationData)
sub, err := c.Subscribe(&opcua.SubscriptionParameters{
Interval: subInterval,
}, notifyCh)
if err != nil {
log.Fatal(err)
}
defer sub.Cancel()
log.Printf("Created subscription with id %v", sub.SubscriptionID)
id, err := ua.ParseNodeID(*nodeID)
if err != nil {
log.Fatal(err)
}
var miCreateRequest *ua.MonitoredItemCreateRequest
var eventFieldNames []string
miCreateRequest = valueRequest(id)
res, err := sub.Monitor(ua.TimestampsToReturnBoth, miCreateRequest)
if err != nil || res.Results[0].StatusCode != ua.StatusOK {
log.Fatal(err)
}
// read from subscription's notification channel until ctx is cancelled
for {
select {
case <-ctx.Done():
return
case res := <-notifyCh:
if res.Error != nil {
log.Print(res.Error)
continue
}
switch x := res.Value.(type) {
case *ua.DataChangeNotification:
for _, item := range x.MonitoredItems {
data := item.Value.Value.Value()
log.Printf("MonitoredItem with client handle %v = %v", item.ClientHandle, data)
}
case *ua.EventNotificationList:
for _, item := range x.Events {
log.Printf("Event for client handle: %v\n", item.ClientHandle)
for i, field := range item.EventFields {
log.Printf("%v: %v of Type: %T", eventFieldNames[i], field.Value(), field.Value())
}
log.Println()
}
default:
log.Printf("what's this publish result? %T", res.Value)
}
}
}
}
func valueRequest(nodeID *ua.NodeID) *ua.MonitoredItemCreateRequest {
handle := uint32(42)
attributeID := ua.AttributeIDValue
filter := ua.DataChangeFilter{}
filter.Trigger = ua.DataChangeTriggerStatusValue
filter.DeadbandType = uint32(ua.DeadbandTypeNone)
filter.DeadbandValue = 0.0
filterExtObj := ua.ExtensionObject{
EncodingMask: ua.ExtensionObjectBinary,
TypeID: &ua.ExpandedNodeID{
NodeID: nodeID,
},
Value: filter,
}
request := &ua.MonitoredItemCreateRequest{
ItemToMonitor: &ua.ReadValueID{
NodeID: nodeID,
AttributeID: attributeID,
DataEncoding: &ua.QualifiedName{},
},
MonitoringMode: ua.MonitoringModeReporting,
RequestedParameters: &ua.MonitoringParameters{
ClientHandle: handle,
DiscardOldest: true,
Filter: &filterExtObj,
QueueSize: 10,
SamplingInterval: 0.0,
},
}
return request
}
发送监控请求时,出现如下错误。
The server does not support the requested monitored item filter. StatusBadMonitoredItemFilterUnsupported (0x80440000)
服务器为Kepware OPC UA服务器,服务器端日志如下,
服务器收到请求
4/15/2021 5:24:07.474 PM [gopcua-1618489446170158449] CreateMonitoredItemsRequest
0000000000: Event started
0000000000: Request Header:
0000000000: authenticationToken: i=2991937600
0000000000: timestamp (UTC): 2021-04-15T12:24:06.180
0000000000: requestHandle: 5
0000000000: returnDiagnostics: 0
0000000000: auditEntryId: [empty]
0000000000: timeoutHint(ms): 10000
0000000000: Parameters:
0000000000: subscriptionId: 16
0000000000: timestampsToReturn: Both
0000000000: monitoredItemCreateRequests []: Size: 1
0000000000: monitoredItemCreateRequests [ 0 ]:
0000000000: itemToMonitor:
0000000000: nodeId: ns=2;s=HONDA.DEV1.T1
0000000000: attributeId: Value
0000000000: indexRange: [empty]
0000000000: dataEncoding: [empty]
0000000000: monitoringMode: Reporting
0000000000: requestedParameters:
0000000000: clientHandle: 42
0000000000: samplingInterval: 0
0000000000: filter:
0000000000: parameterTypeId: 67800040
0000000000: queueSize: 10
0000000000: discardOldest: 1
0000000000: Event complete
服务器发送的响应。
4/15/2021 5:24:07.474 PM [gopcua-1618489446170158449] CreateMonitoredItemsResponse
0000000000: Event started
0000000000: Response Header:
0000000000: timestamp (UTC): 2021-04-15T12:24:07.474
0000000000: requestHandle: 5
0000000000: serviceResult: 0x00000000 (Good)
0000000000: Parameters:
0000000000: monitoredItemCreateResults []: Size: 1
0000000000: monitoredItemCreateResults [ 0 ]:
0000000000: statusCode: 0x80440000 (BadMonitoredItemFilterUnsupported)
0000000000: monitoredItemId: 0
0000000000: revisedSamplingInterval: 0
0000000000: revisedQueueSize: 0
0000000000: filterResult: [empty]
0000000000: Event complete
在我看来,您正在尝试使用您正在为其创建 MonitoredItem 的节点的 NodeId 来构建包含您的过滤器结构的 ExtensionObject,而不是标识您的过滤器结构的 DataTypeEncoding 的 NodeId'正在使用。