Closed djonasdev closed 3 years ago
When you see that the Result value has a BodyType of ByteString, then the decoder did not find the BinaryEncodingId in it's registry.
Looking at the attribute for the type, I think I see some extra quotes:
[BinaryEncodingId("nsu=http://www.siemens.com/simatic-s7-opcua;s=TE_\"\"HTOPC_RecipeInfo\".\"General\"\"")]
Try:
[BinaryEncodingId("nsu=http://www.siemens.com/simatic-s7-opcua;s=TE_\"HTOPC_RecipeInfo\".\"General\"")]
(Sorry for the delay, I'm starting a new job :) )
I'd like to see if we could auto-generate your custom data types using @quinmars project https://github.com/quinmars/UaTypeGenerator
You could share with us the data types of your Siemens S7 PLC program by clicking "Export OPC UA XML file.."
Oh, interesting, I fear the UaTypeGenerator does not support quotes atm. I have to check that.
I have extend UaTypeGenerator to support some of the Siemens oddities, like quotes and nested types. I haven't tested yet if the type library of UaClient will actually find nested types like:
public static class LL1_HMI_Btn
{
/// <summary>
/// Class for the LL1_HMI_Btn._Gate data type.
/// </summary>
[Workstation.ServiceModel.Ua.DataTypeId("nsu=http://www.siemens.com/simatic-s7-opcua;s=DT_\"LL1_HMI_Btn\".\"Gate\"")]
public class _Gate : SimaticStructures
{
/// <summary>
/// Class for the LL1_HMI_Btn._Gate._Q6_2 data type.
/// </summary>
[Workstation.ServiceModel.Ua.DataTypeId("nsu=http://www.siemens.com/simatic-s7-opcua;s=DT_\"LL1_HMI_Btn\".\"Gate\".\"Q6_2\"")]
public class _Q6_2 : SimaticStructures
{
/// <summary>
/// The Open property.
/// </summary>
public DataTyp_HMI_Button Open { get; set; }
I just realized that in my example the BinaryEncodingId is missing, but is also missing in the TIA export file.
Darn.. We're very close. I'll see how to report a issue with Siemens.
Should I consider having the UA Client look up the DefaultEncodingId of each data type in the TypeLibrary upon connecting?
I'd prefer to have the encoding IDs at generation time. I imagine that the binary encoding ID could be easily guessed from the data type ID. Looking at the encoding ID's of @dojo90, it seems I just have to replace the DT_
by a TE_
to get the binary encoding ids. @awcullen can you verify my assumption? I do not have access to a Siemens PLC at the moment. I would than add a switch to UaTypeGenerator that generates the binary encoding ids for Siemens PLCs.
Yes, Siemens replaced the DT by a TE to get the binary encoding ids.
Thanks! Than I will added that to the type generator.
Done.
public static class LL1_HMI_Btn
{
/// <summary>
/// Class for the LL1_HMI_Btn._Gate data type.
/// </summary>
[Workstation.ServiceModel.Ua.BinaryEncodingId("nsu=http://www.siemens.com/simatic-s7-opcua;s=TE_\"LL1_HMI_Btn\".\"Gate\"")]
[Workstation.ServiceModel.Ua.DataTypeId("nsu=http://www.siemens.com/simatic-s7-opcua;s=DT_\"LL1_HMI_Btn\".\"Gate\"")]
public class _Gate : SimaticStructures
{
/// <summary>
/// Class for the LL1_HMI_Btn._Gate._Q6_2 data type.
/// </summary>
[Workstation.ServiceModel.Ua.BinaryEncodingId("nsu=http://www.siemens.com/simatic-s7-opcua;s=TE_\"LL1_HMI_Btn\".\"Gate\".\"Q6_2\"")]
[Workstation.ServiceModel.Ua.DataTypeId("nsu=http://www.siemens.com/simatic-s7-opcua;s=DT_\"LL1_HMI_Btn\".\"Gate\".\"Q6_2\"")]
public class _Q6_2 : SimaticStructures
{
/// <summary>
/// The Open property.
/// </summary>
public DataTyp_HMI_Button Open { get; set; }
@dojo90 you might give it now a try.
Thanks for your efforts š
When you see that the Result value has a BodyType of ByteString, then the decoder did not find the BinaryEncodingId in it's registry.
Looking at the attribute for the type, I think I see some extra quotes:
[BinaryEncodingId("nsu=http://www.siemens.com/simatic-s7-opcua;s=TE_\"\"HTOPC_RecipeInfo\".\"General\"\"")]
Try:
[BinaryEncodingId("nsu=http://www.siemens.com/simatic-s7-opcua;s=TE_\"HTOPC_RecipeInfo\".\"General\"")]
(Sorry for the delay, I'm starting a new job :) )
If I declared the UDTs incorrectly, why can I deserialize the entire object while I can't get the child object deserialized?
I'd like to see if we could auto-generate your custom data types using @quinmars project https://github.com/quinmars/UaTypeGenerator
You could share with us the data types of your Siemens S7 PLC program by clicking "Export OPC UA XML file.."
Unfortunately I could not read the XML. See https://github.com/quinmars/UaTypeGenerator/issues/1
Yes, Siemens replaced the DT by a TE to get the binary encoding ids.
I'd prefer to have the encoding IDs at generation time. I imagine that the binary encoding ID could be easily guessed from the data type ID. Looking at the encoding ID's of @dojo90, it seems I just have to replace the
DT_
by aTE_
to get the binary encoding ids. @awcullen can you verify my assumption? I do not have access to a Siemens PLC at the moment. I would than add a switch to UaTypeGenerator that generates the binary encoding ids for Siemens PLCs.
As you can see from my example, I have already set a "TE" as prefix everywhere. As I said, I can deserialize the whole object, only a part of it does not work.
Is it now necessary to add both attributes (BinaryEncodingId
, DataTypeId
), as exampled here https://github.com/convertersystems/opc-ua-client/issues/174#issuecomment-739572829 ?
When you see that the Result value has a BodyType of ByteString, then the decoder did not find the BinaryEncodingId in it's registry.
Looking at the attribute for the type, I think I see some extra quotes:
[BinaryEncodingId("nsu=http://www.siemens.com/simatic-s7-opcua;s=TE_\"\"HTOPC_RecipeInfo\".\"General\"\"")]
Try:
[BinaryEncodingId("nsu=http://www.siemens.com/simatic-s7-opcua;s=TE_\"HTOPC_RecipeInfo\".\"General\"")]
(Sorry for the delay, I'm starting a new job :) )
I have now tested it again and removed the double quotes. Now it works as expected! Both as a complete object and as a child object. šš
But why it worked with the apparently "incorrect" declaration, you have to find out.
I have a
S7-1500 plc
as an opc server with the following declaration of theStructure
:In my code I use the following
Structure
to successfully encode the completeRecipeInfo
Node
:Have I missed something why I cannot convert the
General
node withGetValueOrDefault<>
? On the other hand, I can easily convert the entireRecipeInfo
Node
and write it back.