Welcome to the new Schneider Electric Community

It's your place to connect with experts and peers, get continuous support, and share knowledge.

  • Explore the new navigation for even easier access to your community.
  • Bookmark and use our new, easy-to-remember address (community.se.com).
  • Get ready for more content and an improved experience.

Contact SchneiderCommunity.Support@se.com if you have any questions.

Close
Invite a Co-worker
Send a co-worker an invite to the Exchange portal.Just enter their email address and we’ll connect them to register. After joining, they will belong to the same company.
Send Invite Cancel
84350members
353529posts

Using automation interface with C# to load history

EcoStruxure Geo SCADA Expert Forum

Find out how SCADA systems and networks, like EcoStruxure Geo SCADA Expert, help industrial organizations maintaining efficiency, processing data for smarter decision making with IoT, RTU and PLC devices.

Solved
DavidSkilbeck
Lt. Commander
Lt. Commander
0 Likes
15
2753

Using automation interface with C# to load history

Hi, I am trying to load history values to a tag. I refer to the last section of the below

 

https://tprojects.schneider-electric.com/telemetry/display/public/CS/Using+the+Automation+Interface+...

 

 

// Get object
ScxV6DbClient.ScxV6Object O = S.FindObject( "New Analogue Point" );

// The line below doesn't work because Interface is declared in the IDL as a vanilla IDispatch, instead we need to use late-binding via Reflection
// O.Interface.LoadDataValues( Values, Times, Qualities );

// Instead, use reflection:
// Get the Historic aggregate
object Historic = O.Interface.GetType().InvokeMember( "Historic", System.Reflection.BindingFlags.GetProperty, null,O.Interface,null );

// Invoke the LoadDataValues method
if ( Historic != null )
  Historic.GetType().InvokeMember( "LoadDataValues", System.Reflection.BindingFlags.InvokeMethod, null, Historic, new object[] { Values, Times, Qualities } );

 

 

I have changed the code to below

 

ScxV6Server S = new ScxV6Server();
S.Connect("Local", "admin", "admin");
// Get object
ScxV6DbClient.ScxV6Object O = S.FindObject("System.Xxxxx.HistoryAnalogPoint");
// Get the Historic aggregate
object Historic = O.Interface.GetType().InvokeMember("Historic", System.Reflection.BindingFlags.GetProperty, null, O.Interface, null);
//// Invoke the LoadDataValues method
if (Historic != null)
    Historic.GetType().InvokeMember("LoadDataValues", System.Reflection.BindingFlags.InvokeMethod, null, Historic, new object[] { sampleGS[i], sampleStartDateTime[i], 192 });

 

When the code gets to the line - ScxV6Server S = new ScxV6Server();

the following error occurs (Class not registered).

 

System.Runtime.InteropServices.COMException
HResult=0x80040154
Message=Retrieving the COM class factory for component with CLSID {EEAD2002-0777-11D2-AF05-0000E82E7A14} failed due to the following error: 80040154 Class not registered (0x80040154 (REGDB_E_CLASSNOTREG)).
Source=DNP3FT
StackTrace:
at InsertHistoryCOMAPI.Program.Main(String[] args) in C:\Users\Administrator\source\repos\\Program.cs:line 186

 

Thanks,


Accepted Solutions
BevanWeiss
Spock
Spock
0 Likes
7
2649

Re: Using automation interface with C# to load history

It's CHistoryBase which has the aggregate.

 

Why are you doing the GetType()?

 

Why not just obtain the Historic aggregate on the object that you want to load the historic data for, and then call InvokeMethod on that aggregate, and pass in the required items...

 

i.e.

aggr.InvokeMethod("LoadDataValue", new object[] {reason, quality, timestamp, value});

or

aggr.InvokeMethod("LoadDataValues", new object[] {valueArray, timestampArray, qualityArray, reasonArray});

or

aggr.InvokeMethod("LoadDataValuesEx", new object[] {valueArray, timestampArray, qualityArray, statusArray, stateArray, reasonArray, msStateArray, putAsideArray} );

 

My offline code example actually shows a version without the new object[] {...}..., and instead just directly passing the arguments after the methodName.  It doesn't match the .NET API help method definition... but it's obviously worked for me at some time.  I haven't fired up Visual Studio to check out the InvokeMethod signature.. maybe it does accept a variable number of arguments.


Lead Control Systems Engineer for Alliance Automation (VIC).
All opinions are my own and do not represent the opinions or policies of my employer, or of my cat..

See Answer In Context

15 Replies 15
AdamWoodland
Commander Commander
Commander
0 Likes
14
2748

Re: Using automation interface with C# to load history

Try

 

new Serck.ScxV6Server()

 

If that doesn't work you may need to regsvr32 DBClient.dll (in the x86 ClearSCADA installation folder), the installer should do that but maybe something went wonky somewhere.

DavidSkilbeck
Lt. Commander
Lt. Commander
0 Likes
13
2745

Re: Using automation interface with C# to load history

Hi, I added the Serk, it still had an  error.

However, I removed the Serk and after that all errors cleared.

I am now able to run the code further.

 

@AdamWoodland 

I find it unclear at the moment, what is the format it is looking for as regards to Values, Times, Qualities.

Historic.GetType().InvokeMember( "LoadDataValues", System.Reflection.BindingFlags.InvokeMethod, null, Historic, new object[] { Values, Times, Qualities } );

Should it be more { Value, Time, Quality }? Value = 4.45, Time = 2021/02/24 12:30:22:55, Quality = 192?
If I can get it to write one value to the history of a point it would be a start.

Thanks,

BevanWeiss
Spock
Spock
0 Likes
12
2698

Re: Using automation interface with C# to load history

What does the schema say the arguments to LoadDataValues should be?


Lead Control Systems Engineer for Alliance Automation (VIC).
All opinions are my own and do not represent the opinions or policies of my employer, or of my cat..
AdamWoodland
Commander Commander
Commander
0 Likes
11
2681
DavidSkilbeck
Lt. Commander
Lt. Commander
0 Likes
10
2679

Re: Using automation interface with C# to load history

Thanks Adam, I hadn't found that.

Thanks,

 

Hi, I notice the later article indicates four parameters

 LoadDataValue( Value{Variant},
                Timestamp{Time},
                Quality{Long},
                Reason{Byte} )

where the first indicates three

{ Values, Times, Qualities }

which should it be?

 

So I have tried

 

{ sampleGS[i], sampleStartDateTime[i], sampleQuality[i], sampleReason[i] }

 


which when written to the console looks like
4.0218887,2020,07,22,16,11,38,010,192,8 this may not be correct format?


This throws an error

 

 

System.Reflection.TargetInvocationException
HResult=0x80131604
Message=Exception has been thrown by the target of an invocation.
Source=System.Private.CoreLib
StackTrace:
at System.RuntimeType.InvokeDispMethod(String name, BindingFlags invokeAttr, Object target, Object[] args, Boolean[] byrefModifiers, Int32 culture, String[] namedParameters)
at System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams)
at System.Type.InvokeMember(String name, BindingFlags invokeAttr, Binder binder, Object target, Object[] args)
at InsertHistoryCOMAPI.Program.Main(String[] args) in C:\Users\Administrator\source\repos\Xxxxx\Program.cs:line 200

Inner Exception 1:
ArgumentException: Value does not fall within the expected range.

 

 

Thanks,

Tags (1)
BevanWeiss
Spock
Spock
0 Likes
9
2661

Re: Using automation interface with C# to load history

If using C# recommendations are:

 

LoadDataValues requires ARRAYS, not single values

LoadDataValue requires single values, not arrays

 

You should use DateTimeOffset as DateTime inputs to functions, and expect DateTimeOffset as return values.

You shouldn't explicitly "box" 'Value' (variant) datatypes, you can use the native intrinsic type just fine.


Lead Control Systems Engineer for Alliance Automation (VIC).
All opinions are my own and do not represent the opinions or policies of my employer, or of my cat..
DavidSkilbeck
Lt. Commander
Lt. Commander
0 Likes
8
2655

Re: Using automation interface with C# to load history

Hi Bevan,

where in the schema were you referring to above please.

 

ok, I will try LoadDataValue.
Can any body give correct variable type and values that I can place into the line below, that they know works, so that I can at least see it work please.

Historic.GetType().InvokeMember("LoadDataValue", System.Reflection.BindingFlags.InvokeMethod, null, Historic, new object[] { sampleValueTest, sampleStartDateTimeTest, sampleQualityTest });

 

sampleValueTest

 

sampleStartDateTimeTest

sampleQualityTest

 

Thanks,

BevanWeiss
Spock
Spock
0 Likes
7
2650

Re: Using automation interface with C# to load history

It's CHistoryBase which has the aggregate.

 

Why are you doing the GetType()?

 

Why not just obtain the Historic aggregate on the object that you want to load the historic data for, and then call InvokeMethod on that aggregate, and pass in the required items...

 

i.e.

aggr.InvokeMethod("LoadDataValue", new object[] {reason, quality, timestamp, value});

or

aggr.InvokeMethod("LoadDataValues", new object[] {valueArray, timestampArray, qualityArray, reasonArray});

or

aggr.InvokeMethod("LoadDataValuesEx", new object[] {valueArray, timestampArray, qualityArray, statusArray, stateArray, reasonArray, msStateArray, putAsideArray} );

 

My offline code example actually shows a version without the new object[] {...}..., and instead just directly passing the arguments after the methodName.  It doesn't match the .NET API help method definition... but it's obviously worked for me at some time.  I haven't fired up Visual Studio to check out the InvokeMethod signature.. maybe it does accept a variable number of arguments.


Lead Control Systems Engineer for Alliance Automation (VIC).
All opinions are my own and do not represent the opinions or policies of my employer, or of my cat..
DavidSkilbeck
Lt. Commander
Lt. Commander
0 Likes
6
2603

Re: Using automation interface with C# to load history

Hi, I was attempting to follow the below,

 

 

// Get object
ScxV6DbClient.ScxV6Object O = S.FindObject( "New Analogue Point" );

// The line below doesn't work because Interface is declared in the IDL as a vanilla IDispatch, instead we need to use late-binding via Reflection
// O.Interface.LoadDataValues( Values, Times, Qualities );

// Instead, use reflection:
// Get the Historic aggregate
object Historic = O.Interface.GetType().InvokeMember( "Historic", System.Reflection.BindingFlags.GetProperty, null,O.Interface,null );

// Invoke the LoadDataValues method
if ( Historic != null )
  Historic.GetType().InvokeMember( "LoadDataValues", System.Reflection.BindingFlags.InvokeMethod, null, Historic, new object[] { Values, Times, Qualities } );

 

 

I thought this would allow for data to be loaded into the history of the point.

Thanks,

 

BevanWeiss
Spock
Spock
0 Likes
5
2596

Re: Using automation interface with C# to load history

Here's something from @sbeadle , it's where I'd start from... 

https://github.com/GeoSCADA/Utilities-and-Examples/blob/main/InsertHistoricData/Program.cs

 

His LoadDataValue example

// Add a value
Object[] p1 = new Object[4];
p1[0] = 1;
p1[1] = 192;
p1[2] = now;
p1[3] = 1;
PointObj.Aggregates["Historic"].InvokeMethod("LoadDataValue", p1);

 

Although I prefer the inline definition of the new object[] {} (as my previous example used)

 

He's got another example here:

https://github.com/GeoSCADA/Utilities-and-Examples/blob/main/SetInternalPoint/Program.cs

where he uses InvokeMethod on the base object (i.e. PointObj from the above example) but has a longer qualifier on the method name ("Historic.RawValues" in this version... but that would be "Historic.LoadDataValue" if you wanted to invoke the LoadDataValue method instead).

 

The tproject concept has quite a lot of jumping backwards through hoops, which seems unnecessary.

Perhaps back when it was created the Aggregates collection didn't exist.


Lead Control Systems Engineer for Alliance Automation (VIC).
All opinions are my own and do not represent the opinions or policies of my employer, or of my cat..
DavidSkilbeck
Lt. Commander
Lt. Commander
0 Likes
4
2594

Re: Using automation interface with C# to load history

Hi, I went back through some older code I had and came across this.

I just changed the date and this worked.
Apart from having to change the date to a more recent one of course.

 

 

 

 

DBObject TestPoint;
                Aggregate HistAgg;

                //Object[] argsTo;
                DateTime dt;
                Object[] argsTo = new Object[4];

                using (Connection conn = new Connection("ClearSCADA"))
                {

                    // Connect to local server
                    SecureString passwd = new SecureString();
                    string strPassword = "admin";
                    foreach (char c in strPassword)
                        passwd.AppendChar(c);
                    passwd.MakeReadOnly();
                    conn.Connect("localhost");
                    conn.LogOn("admin", passwd);
                    



                    //string pointValue = dict["Test2"];
                    // Get the point
                    TestPoint = conn.GetObject("System.Dashboard.Engineering Dashboard.Work Orders.Points.HistoryAnalogPoint");
                    // If Historic is enabled for the point, insert historic data
                    if (TestPoint.Aggregates.TryGetValue("Historic", out HistAgg) == true)
                    {

                        argsTo[0] = "4"; // Reason
                                         //argsTo[0] = column1[0]; 
                                         //argsTo[1] = "1"; // Quality
                        argsTo[1] = "192"; // Quality
                                           //argsTo[1] = column3[0]; // Quality
                        dt = new DateTime(2020, 3, 02, 11, 55, 52);
                        argsTo[2] = new System.DateTimeOffset(dt);
                        //argsTo[2] = column2[0]; //DateTime
                        //argsTo[3] = "88";
                        ////argsTo[3] = column4[0]; //Value
                        argsTo[3] = 4.45; //Value

                        HistAgg.InvokeMethod("LoadDataValue", argsTo);
                        
                    }
                    conn.LogOff();
                    conn.Disconnect();

 

 

Thanks, 

DavidSkilbeck
Lt. Commander
Lt. Commander
0 Likes
3
2581

Re: Using automation interface with C# to load history

Hi, these are the settings for my Geo SCADA.

ErrorMessageCSV4Import.png

 

This a sample of the data I want to import
4.0218887,2020,07,22,16,11,38,010,192,8
3.1718216,2020,07,22,16,11,53,010,192,8

This is what I am getting in Geo SCADA

 

 

If I use the below it wont import historic values

dt = new DateTime(2020, 2, 26, 11, 55, 52);

If I change the 2020 to 2021 it imports.

BevanWeiss
Spock
Spock
0 Likes
2
2570

Re: Using automation interface with C# to load history

Assuming that you were running your code at close to 5pm on the 26th February 2021... and you have a historic configuration set to keep data for 52 weeks... then 52*7 = 364 days... so the 26th February 2020 is NOT within your configured historic retention window.

In fact you're two days out, since last year was a leap year..

 

You should go back through the help files for the settings in the Server Configuration pane, really see what it says for each of the fields, and think about how that will relate to what you are trying to do.


Lead Control Systems Engineer for Alliance Automation (VIC).
All opinions are my own and do not represent the opinions or policies of my employer, or of my cat..
DavidSkilbeck
Lt. Commander
Lt. Commander
0 Likes
1
1604

Re: Using automation interface with C# to load history

Hi, is it possible to change the code above to do a LoadDataFile.

Thanks,

BevanWeiss
Spock
Spock
0 Likes
0
1539

Re: Using automation interface with C# to load history

Yes, you'll just want to look at the schema to see what arguments you need to supply to that method, and note that the path must be:

  1. On the running MAIN server
  2. Accessible under the permissions that the Geo SCADA Expert server instance is running under (inclusive of both username and escalation settings)
  3. Using the correct path information to reach the file (given the server is not running in the same context as you may be running your script in)

Lead Control Systems Engineer for Alliance Automation (VIC).
All opinions are my own and do not represent the opinions or policies of my employer, or of my cat..