Open GWS65 opened 2 years ago
This is how I've been using the library to write different types of data. Maybe it will help you:
// value is an interface{}
// the type in go should be similar to the type set for the node on your opc ua server
v, err := ua.NewVariant(value)
// idString should be something like ns=3;i=1001
id, err := ua.ParseNodeID(idString)
// build the request with one or more nodes
request := &ua.WriteRequest{
NodesToWrite: []*ua.WriteValue{
{
NodeID: id,
AttributeID: ua.AttributeIDValue,
Value: &ua.DataValue{
EncodingMask: ua.DataValueValue,
Value: v,
},
},
},
}
// make the request and get the response
resp, err := s.client.Write(request)
Hello Jeff,
Thanks for your answer. As stated before I am new to Golang and that is probably the biggest issue here. However from you response I don't see how to know the type of value maybe something as value.GetType() could do that trick or simply reading the node and determine the type of the nodevalue from there?
Issue I ran into was that based on example from the gopcua\examples\write\write.go it was working fine for a text datatype but not dor an uint32 datatype. Als trying to cast the text "123" into unt32 123 did give me an error.
Meanwhile I have created three separate programs that can write [ text, uint32, bool ] values successfully but creating a separate program per datatype does not seem like a good idea.
What I am trying to achieve is something like: (in pseudocode)
writeValue (nodeID, Value) cast value to datatype op nodeID use v, err "= ua.newVariant(value) to construct the data for writing to OPCUA server (Kepware in my case) write UA value(s)
The end result should be a program that can read or write OPCUA nodes directly and it's purpose is to support scripting. In many cases the data type that is read from a csv file is not 100% clear. 123 could be int uint in in 16 32 or 64 bits. OPCUA needs the exact type.
Do you thin the best way would be to first read the node and determine the exact data type and (try to) cast to that type? If successful than write the cast value..
Thanks for your advise.
GWS65
Met vriendelijke groeten, Gert-Wim Scheppink
On Sat, Jul 2, 2022 at 8:28 PM Jeff Titus @.***> wrote:
This is how I've been using the library to write different types of data. Maybe it will help you:
// value is an interface{}// the type in go should be similar to the type set for the node on your opc ua serverv, err := ua.NewVariant(value) // idString should be something like ns=3;i=1001id, err := ua.ParseNodeID(idString) // build the request with one or more nodesrequest := &ua.WriteRequest{ NodesToWrite: []*ua.WriteValue{ { NodeID: id, AttributeID: ua.AttributeIDValue, Value: &ua.DataValue{ EncodingMask: ua.DataValueValue, Value: v, }, }, }, } // make the request and get the responseresp, err := s.client.Write(request)
reference https://github.com/SE-I-T-Digital/device-opcua-go/blob/main/internal/server/writehandler.go#L49-L67
— Reply to this email directly, view it on GitHub https://github.com/gopcua/opcua/issues/590#issuecomment-1172941226, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABYGPNLDUADGQ3MFIFCZ5H3VSCC2RANCNFSM52HKCOQQ . You are receiving this because you authored the thread.Message ID: @.***>
@GWS65 I'm curious how you are defining value
and casting the data right now. You could try adding the spf13/cast
package to your program and use v, err := ua.NewVariant(cast.ToUint32(value))
.
An example of what that package can do:
package main
import (
"fmt"
"github.com/spf13/cast"
)
func main() {
var value string = "42"
fmt.Printf("Type of value is %T\n", value) // Type of value is string
fmt.Printf("Type of value is %T\n", cast.ToUint32(value)) // Type of value is uint32
}
I do think you have a special case here that needs to be handled in your logic:
In many cases the data type that is read from a csv file is not 100% clear. 123 could be int uint in in 16 32 or 64 bits. OPCUA needs the exact type.
Your options would be to either make sure the data types in the file are more specific (maybe not possible, I imagine), or as you said, read metadata about the node on the server to retrieve its type, then use a switch statement and cast
to construct the correctly typed value and write to the server.
Hello Jeff,
Thanks for your quick response. All my ‘prpgrams’are based on the write.go sample a bit modified to get other daattypes.
In my quest on how to cas tin go I ran into an example that uses strconv.Parse….
For Bool I used this:
myBool, err := strconv.ParseBool(*value)
if err != nil {
fmt.Println(err)
log.Fatalf("string to uint32 error: %myBool", err)
}
v, err := ua.NewVariant(myBool)
if err != nil {
log.Fatalf("invalid value: %v", err)
}
req := &ua.WriteRequest{
NodesToWrite: []*ua.WriteValue{
{
NodeID: id,
AttributeID: ua.AttributeIDValue,
Value: &ua.DataValue{
EncodingMask: ua.DataValueValue,
Value: v,
},
},
},
}
And also I used .ParsUint() which returns an Uin64 that needs to be converted to Uin32..
switch *valuetype {
case "uint32":
myInt, err := strconv.ParseUint(*value, 10, 32)
if err != nil {
fmt.Println(err)
log.Fatalf("string to uint32 error: %myInt", err)
}
v, err := ua.NewVariant(uint32(myInt))
if err != nil {
log.Fatalf("invalid value: %v", err)
}
fmt.Print(v)
I think your example would do a better job but I still need to determinie the type from the node to make sure. I will spend some time on that approach soon.
Alternative for me is that in most cases I know the type and can program it up front in mu script and pass it as a parameter.
Your .cast module will help and I will test it for that.
Thanks a lot!
GWS65
From: Jeff Titus @.> Sent: maandag 4 juli 2022 19:43 To: gopcua/opcua @.> Cc: GWS65 @.>; Mention @.> Subject: Re: [gopcua/opcua] Write uint32 value to server --> error badType (Issue #590)
@GWS65 https://github.com/GWS65 I'm curious how you are defining value and casting the data right now. You could try adding the https://github.com/spf13/cast spf13/cast package to your program and use v, err := ua.NewVariant(cast.ToUint32(value)).
An example of what that package can do:
package main
import ( "fmt" "github.com/spf13/cast" )
func main() { var value string = "42" fmt.Printf("Type of value is %T\n", value) // Type of value is string fmt.Printf("Type of value is %T\n", cast.ToUint32(value)) // Type of value is uint32 }
I do think you have a special case here that needs to be handled in your logic:
In many cases the data type that is read from a csv file is not 100% clear. 123 could be int uint in in 16 32 or 64 bits. OPCUA needs the exact type.
Your options would be to either make sure the data types in the file are more specific (maybe not possible, I imagine), or as you said, read metadata about the node on the server to retrieve its type, then use a switch statement and cast to construct the correctly typed value and write to the server.
— Reply to this email directly, view it on GitHub https://github.com/gopcua/opcua/issues/590#issuecomment-1174032269 , or unsubscribe https://github.com/notifications/unsubscribe-auth/ABYGPNNQ3UG3IN3DPUR5CDLVSMPBZANCNFSM52HKCOQQ . You are receiving this because you were mentioned. https://github.com/notifications/beacon/ABYGPNIGRWXK3ZSY6JCNNRLVSMPBZA5CNFSM52HKCOQ2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOIX5E7DI.gif Message ID: @. @.> >
Hello,
Thanks for the library and all we can do with it with just a little code.
I am quite new to GoLang and my issue is that I am trying to modify example write.go to write an uint32 to a KepWareEXV6 server. Whatever I try I kept getting the error: The value supplied for the attribute is not of the same type as the attribute's value. StatusBadTypeMismatch (0x80740000) as soon as my value parameter and the OPC tag are not of type String. For String it works as expected.
So the issue seems to be to detect the datatype and act accordingly. Could not find any good example code related to gopcua. Could you advise on how to handle different datatypes for writing?
even better provide an example on how to write the different datatypes to the server using one routine passing the datatype or have the routine analyse it itself. It appears to me as if the issue is that parameter is passed as string and it needs conversion/cast to correct type before using ua.NewVariant(*value) but could not make that work.
ended up creating three programs for three different data types :(
Any example would be very much appreciated!
GWS65