Getting BadMonitoredItemFilterUnsupported (0x80440000)

0

I'm using GOPCUA v0.2.0-rc2 library to connect to an OPC UA server. Everything works fine if I don't use any filter in the monitoring items. But I want to use datachange filter to be able to receive values only when they change by some percentage or absolute value. Following is the complete code.

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
}

When the monitoring request is sent, I get following error.

The server does not support the requested monitored item filter. StatusBadMonitoredItemFilterUnsupported (0x80440000)

The server is Kepware OPC UA server, and the logs on the server side are below,

The request received by server

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

The response sent by server.

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
go
opc-ua
opc
asked on Stack Overflow Apr 15, 2021 by Salman Azmat • edited Apr 15, 2021 by Salman Azmat

1 Answer

1

It looks to me like you're trying to build the ExtensionObject that contains your filter structure using the NodeId of the Node you're creating a MonitoredItem for instead of the NodeId that identifies the DataTypeEncoding of the filter structure you're using.

answered on Stack Overflow Apr 15, 2021 by Kevin Herron

User contributions licensed under CC BY-SA 3.0