diff --git a/plugins/inputs/opcua/README.md b/plugins/inputs/opcua/README.md index fe5308973cba2..f9f8bb71b7856 100644 --- a/plugins/inputs/opcua/README.md +++ b/plugins/inputs/opcua/README.md @@ -96,6 +96,7 @@ Plugin minimum tested version: 1.16 ## Set additional valid status codes, StatusOK (0x0) is always considered valid # additional_valid_status_codes = ["0xC0"] + # [inputs.opcua.request_workarounds] ## Use unregistered reads instead of registered reads # use_unregistered_reads = false ``` @@ -109,7 +110,7 @@ An OPC UA node ID may resemble: "ns=3;s=Temperature". In this example: - This example temperature node has a value of 79.0 To gather data from this node enter the following line into the 'nodes' property above: -```shell +```text {field_name="temp", namespace="3", identifier_type="s", identifier="Temperature"}, ``` @@ -156,16 +157,13 @@ This example group configuration has two groups with two nodes each: ## Connection Service -This plugin actively reads to retrieve data from the OPC server. -This is done every `interval`. +This plugin actively reads to retrieve data from the OPC server. +This is done every `interval`. ## Metrics The metrics collected by this input plugin will depend on the configured `nodes` and `group`. -## Metrics - -Metrics are produced according to the defined node ID and group configuration. ## Example Output diff --git a/plugins/inputs/opcua/opcua_reader.go b/plugins/inputs/opcua/opcua_reader.go index 35b1c93270157..0b9cf18e85424 100644 --- a/plugins/inputs/opcua/opcua_reader.go +++ b/plugins/inputs/opcua/opcua_reader.go @@ -14,8 +14,9 @@ import ( type OpcUaReader struct { ReadClientConfig + Log telegraf.Logger `toml:"-"` + client *ReadClient - Log telegraf.Logger `toml:"-"` } //go:embed sample.conf @@ -26,9 +27,10 @@ func (*OpcUaReader) SampleConfig() string { } // Init Initialise all required objects -func (o *OpcUaReader) Init() (err error) { +func (o *OpcUaReader) Init() error { + var err error o.client, err = o.ReadClientConfig.CreateReadClient(o.Log) - return + return err } // Gather defines what data the plugin will gather. diff --git a/plugins/inputs/opcua/opcua_reader_test.go b/plugins/inputs/opcua/opcua_reader_test.go index 9baefd8c8c6ee..3ad0a1f0c11f0 100644 --- a/plugins/inputs/opcua/opcua_reader_test.go +++ b/plugins/inputs/opcua/opcua_reader_test.go @@ -44,6 +44,9 @@ nodes = [{name="name4", identifier="4000", tags=[["tag1", "override"]]}] [inputs.opcua.workarounds] additional_valid_status_codes = ["0xC0"] + +[inputs.opcua.request_workarounds] +use_unregistered_reads = true ` c := config.NewConfig() @@ -105,4 +108,5 @@ additional_valid_status_codes = ["0xC0"] }, }, o.ReadClientConfig.Groups) require.Equal(t, opcua.OpcUAWorkarounds{AdditionalValidStatusCodes: []string{"0xC0"}}, o.ReadClientConfig.Workarounds) + require.Equal(t, ReadClientWorkarounds{UseUnregisteredReads: true}, o.ReadClientConfig.ReadClientWorkarounds) } diff --git a/plugins/inputs/opcua/read_client.go b/plugins/inputs/opcua/read_client.go index 7f095b76dde36..820f0c5384e6d 100644 --- a/plugins/inputs/opcua/read_client.go +++ b/plugins/inputs/opcua/read_client.go @@ -5,12 +5,17 @@ import ( "fmt" "github.com/gopcua/opcua/ua" "github.com/influxdata/telegraf" - opcuaclient "github.com/influxdata/telegraf/plugins/common/opcua" + "github.com/influxdata/telegraf/plugins/common/opcua" "github.com/influxdata/telegraf/plugins/common/opcua/input" "github.com/influxdata/telegraf/selfstat" ) +type ReadClientWorkarounds struct { + UseUnregisteredReads bool `toml:"use_unregistered_reads"` +} + type ReadClientConfig struct { + ReadClientWorkarounds ReadClientWorkarounds `toml:"request_workarounds"` input.InputClientConfig } @@ -20,6 +25,7 @@ type ReadClient struct { ReadSuccess selfstat.Stat ReadError selfstat.Stat + Workarounds ReadClientWorkarounds // internal values req *ua.ReadRequest @@ -39,6 +45,7 @@ func (rc *ReadClientConfig) CreateReadClient(log telegraf.Logger) (*ReadClient, OpcUAInputClient: inputClient, ReadSuccess: selfstat.Register("opcua", "read_success", tags), ReadError: selfstat.Register("opcua", "read_error", tags), + Workarounds: rc.ReadClientWorkarounds, }, nil } @@ -48,21 +55,28 @@ func (o *ReadClient) Connect() error { return err } - regResp, err := o.Client.RegisterNodes(&ua.RegisterNodesRequest{ - NodesToRegister: o.NodeIDs, - }) - if err != nil { - return fmt.Errorf("registerNodes failed: %v", err) - } - readValueIds := make([]*ua.ReadValueID, len(o.NodeIDs)) - for i, v := range regResp.RegisteredNodeIDs { - readValueIds[i] = &ua.ReadValueID{NodeID: v} + if o.Workarounds.UseUnregisteredReads { + for i, nid := range o.NodeIDs { + readValueIds[i] = &ua.ReadValueID{NodeID: nid} + } + } else { + regResp, err := o.Client.RegisterNodes(&ua.RegisterNodesRequest{ + NodesToRegister: o.NodeIDs, + }) + if err != nil { + return fmt.Errorf("registerNodes failed: %v", err) + } + + for i, v := range regResp.RegisteredNodeIDs { + readValueIds[i] = &ua.ReadValueID{NodeID: v} + } } + o.req = &ua.ReadRequest{ MaxAge: 2000, - NodesToRead: readValueIds, TimestampsToReturn: ua.TimestampsToReturnBoth, + NodesToRead: readValueIds, } err = o.read() @@ -74,7 +88,7 @@ func (o *ReadClient) Connect() error { } func (o *ReadClient) ensureConnected() error { - if o.State == opcuaclient.Disconnected { + if o.State == opcua.Disconnected { err := o.Connect() if err != nil { return err @@ -91,7 +105,7 @@ func (o *ReadClient) CurrentValues() ([]telegraf.Metric, error) { } err = o.read() - if err != nil && o.State == opcuaclient.Connected { + if err != nil && o.State == opcua.Connected { // We do not return the disconnect error, as this would mask the // original problem, but we do log it disconnectErr := o.Disconnect(context.Background()) diff --git a/plugins/inputs/opcua/sample.conf b/plugins/inputs/opcua/sample.conf index 43a00582eea3e..66b6170a4d866 100644 --- a/plugins/inputs/opcua/sample.conf +++ b/plugins/inputs/opcua/sample.conf @@ -86,5 +86,6 @@ ## Set additional valid status codes, StatusOK (0x0) is always considered valid # additional_valid_status_codes = ["0xC0"] + # [inputs.opcua.request_workarounds] ## Use unregistered reads instead of registered reads # use_unregistered_reads = false diff --git a/plugins/inputs/opcua_listener/README.md b/plugins/inputs/opcua_listener/README.md index 3512c8edbd350..ba463349ebc98 100644 --- a/plugins/inputs/opcua_listener/README.md +++ b/plugins/inputs/opcua_listener/README.md @@ -110,7 +110,7 @@ An OPC UA node ID may resemble: "ns=3;s=Temperature". In this example: - This example temperature node has a value of 79.0 To gather data from this node enter the following line into the 'nodes' property above: -```shell +```text {field_name="temp", namespace="3", identifier_type="s", identifier="Temperature"}, ``` @@ -157,9 +157,9 @@ This example group configuration has two groups with two nodes each: ## Connection Service -This plugin subscribes to the specified nodes to receive data from -the OPC server. The updates are received at most as fast as the -`subscription_interval`. +This plugin subscribes to the specified nodes to receive data from +the OPC server. The updates are received at most as fast as the +`subscription_interval`. ## Metrics diff --git a/plugins/inputs/opcua_listener/opcua_listener.go b/plugins/inputs/opcua_listener/opcua_listener.go index 4a5738375be84..fd03444fb97eb 100644 --- a/plugins/inputs/opcua_listener/opcua_listener.go +++ b/plugins/inputs/opcua_listener/opcua_listener.go @@ -24,9 +24,10 @@ func (*OpcUaListener) SampleConfig() string { return sampleConfig } -func (o *OpcUaListener) Init() (err error) { +func (o *OpcUaListener) Init() error { + var err error o.client, err = o.SubscribeClientConfig.CreateSubscribeClient(o.Log) - return + return err } func (o *OpcUaListener) Gather(_ telegraf.Accumulator) error {