Code-Beispiele

Dieses Kapitel beschreibt wie WinCC OA C# Manager API verwendet werden kann. Das Kapitel enthält Executable Code-Beispiele. Den vollständigen Sourcecode des Beispiels finden Sie im letzten Abschnitt dieses Kapitels.

1. Neuen Manager erstellen

Folgen Sie den Anweisungen des Kapitels C# API-Manager erstellen und löschen Sie den Code der Klasse "Samples". Die Klasse sollte wie folgt aussehen:

using System;
using System.Threading.Tasks;
using ETM.WCCOA;
namespace GettingStarted
{
  class Samples
  {
    static OaManager _managerInstance = null;
    public Samples()
    {
      PrintSampleUsage();
    }
    public void PrintSampleUsage()
    {
      Console.Clear();
      Console.WriteLine("Press key 1 - 9 to run sample code:");
      Console.WriteLine("1     Create a new Manager");
      Console.WriteLine("2     Establish a connection");
      Console.WriteLine("3     Read an online value from WinCC OA sync + async");
      Console.WriteLine("4     Write a value to WinCC OA async");
      Console.WriteLine("5     Query value changes");
      Console.WriteLine("6     Create a data point using ProcessModel");
      Console.WriteLine("7     Query current alerts using a SELECT statement");
      Console.WriteLine("8     Query historical values");
      Console.WriteLine("9     Complete sample");
      Console.WriteLine("ESC   Exit sample");
    }
  }
}

2. Verbindung aufbauen

Bauen Sie eine Verbindung zu einem WinCC OA-Projekt über die Programmargumente (über die Kommandozeilenoptionen) auf. Kopieren Sie den Sourcecode in Ihr leeres Projekt.

class Program
using System;
using System.Threading.Tasks;
using ETM.WCCOA;
namespace GettingStarted
{
  class Samples
  {
    static OaManager _managerInstance = null;
    public Samples()
    {
      PrintSampleUsage();
    }
    public void PrintSampleUsage()
    {
      Console.Clear();
      Console.WriteLine("Press key 1 - 9 to run sample code:");
      Console.WriteLine("1     Create a new Manager");
      Console.WriteLine("2     Establish a connection");
      Console.WriteLine("3     Read an online value from WinCC OA sync + async");
      Console.WriteLine("4     Write a value to WinCC OA async");
      Console.WriteLine("5     Query value changes");
      Console.WriteLine("6     Create a data point using ProcessModel");
      Console.WriteLine("7     Query current alerts using a SELECT statement");
      Console.WriteLine("8     Query historical values");
      Console.WriteLine("9     Complete sample");
      Console.WriteLine("ESC   Exist sample");
    }
    // SAMPLE 1: Create a Manager object
    public OaManager ManagerInstance
    {
      get
      {
        // Singleton design pattern - ensure that only one manager object is created
        if (_managerInstance == null)
          _managerInstance = OaSdk.CreateManager();
        return _managerInstance;
      }
    }
    // SAMPLE 2: Establish connection to the WinCC OA project
    public async Task<int>EstablishConection(string[] args)
    {
      // Initialize manager configuration
      ManagerInstance.Init(ManagerSettings.DefaultApiSettings, args);
      // Start the manager
      await ManagerInstance.StartAsync();
      // Inform about the connection. Console output is shown in the WinCC OA logviewer
      Console.WriteLine("Connection to project established");
      return 1;
    }
  }
}

3. Lesen Sie einen Online-Wert aus WinCC OA

Das erste Beispiel liest einen Online-Wert über die synchrone Version der Funktion GetDpValue() aus dem WinCC OA-Projekt. Führen Sie das Beispiel aus indem Sie den Code in die Program-Klasse kopieren und ReadValuesExample() aus der main()-Funktion aufrufen:.

// SAMPLE 3: Read an online value from WinCC OA
public void ReadValuesExample()
{
  // Get access to the ProcessValues
  OaProcessValues valueAccess = ManagerInstance.ProcessValues;
  // Calling GetDpValue via an "Access" object
  OaDpValueItem myFloatItem = valueAccess.GetDpValue("ExampleDP_Arg1.");
  // Read a property DpValue from an OaDpValue item
  double myFloatVal1 = myFloatItem.DpValue;
  // This could also be done in one line with
  double myFloatVal2 = valueAccess.GetDpValue("ExampleDP_Arg1.").DpValue;
  // Read more than one value
  string[] myValuesToRead = { "ExampleDP_Arg1.", "ExampleDP_AlertHdl1." };
  var myResultCollection = valueAccess.GetDpValue(myValuesToRead);
  // Go through the answer collection
  foreach (var item in myResultCollection)
  {
    Console.WriteLine(item.DpValue.ToString());
  }
}

Das Beispiel liest einen Onlinewert über die asynchrone Version GetDpValueAsync() aus dem WinCC OA-Projekt. Führen Sie das Beispiel aus indem Sie den Code in die Program-Klasse kopieren und ReadValuesExampleAsync().Wait() aus der main()-Funktion aufrufen:.

// SAMPLE 3b: Read an online value from WinCC OA async
public async Task ReadValuesExampleAsync()
{
  // Get access to the ProcessValues
  OaProcessValues valueAccess = ManagerInstance.ProcessValues;
  // Calling GetDpValue via an "Access" object
  OaDpValueItem myFloatItem = await valueAccess.GetDpValueAsync("ExampleDP_Arg1.");
  // Read property DpValue from OaDpValue item
  double myFloatVal1 = myFloatItem.DpValue;
  // Without await, the async value returns a Task object which could be awaited later on
  Task<OaDpValueItem> myTaskToWait = valueAccess.GetDpValueAsync("ExampleDP_Arg1.");
  // Do some work in between
  Console.WriteLine("Do some work while waiting for value");
  // Wait for the result and get a result value directly
  var myFloatIVal2 = (await myTaskToWait).DpValue;
}

4. Schreibe einen Wert auf einen Datenpunkt.

Das folgende Beispiel schreibt den Float-Wert 4.2 auf den Datenpunkt “ExampleDP_Arg1.” Führen Sie das Beispiel aus indem Sie den Code in die Program-Klasse kopieren und WriteValuesExampleAsync().Wait() aus der main()-Funktion aufrufen:.

// SAMPLE 4. Write a value to WinCC OA
public async Task WriteValuesExampleAsync()
{
  // Get access to the ProcessValues
  OaProcessValues valueAccess = ManagerInstance.ProcessValues;
  // Calling SetDpValue via an "Access" object. SetDpValue waits for an answer from
  // the Event Manager
  await valueAccess.SetDpValueAsync("ExampleDP_Arg1.", 4.2);
  // Calling FireDpValue. FireDpValue does not wait for the answer from the Event Manager
  // (therefore an async variant is not necessary)
  valueAccess.FireDpValue("ExampleDP_Arg1.", 77.2);
  // Set a collection of values with a specific time
  await valueAccess.SetDpValueAsync(DateTime.Now.AddSeconds(2),
  new Tuple<string, OaVariant>("ExampleDP_Arg1.", (double)7.7),
  new Tuple<string, OaVariant>("ExampleDP_AlertHdl1.", (bool)false));
}

5. Abfrage von Wertänderungen

Das folgende Beispiel fragt Wert- und Zeitstempel-Änderungen der Datenpunkte “ExampleDP_Arg1.” und “ExampleDP_Arg2.” ab. Führen Sie das Beispiel aus indem Sie den Code in die Program-Klasse kopieren und SubscribeOnValueChangesExampleAsync().Wait() aus der main()-Funktion aufrufen:.

// SAMPLE 5: Query value changes
public async Task SubscribeOnValueChangesExampleAsync()
{
  // Get access to the ProcessValues
  OaProcessValues valueAccess = ManagerInstance.ProcessValues;
  // Create "Subscription"-object
  OaDpValueSubscription mySubscription = valueAccess.CreateDpValueSubscription();
  // Append datapoints to subscribe to
  mySubscription.AddDp("ExampleDP_Arg1.");
  mySubscription.AddDp("ExampleDP_Arg1.:_online.._stime");
  mySubscription.AddDp("ExampleDP_Arg2.");
  mySubscription.AddDp("ExampleDP_Arg2.:_online.._stime");
  // Define delegate function for value changed event. Can be done as shown here.
  //Either as a Lambda function or as a separate function
  mySubscription.SingleValueChanged += (vcsender, vce) =>
  {
    if (vce.IsAnswer)
      Console.WriteLine("FirstAnswer: " + vce.Value.DpValue.ToString());
    else
      Console.WriteLine("ValueChange: " + vce.Value.DpValue.ToString());
  };
  // If FireChangedEventForAnswer is set to true, the ValueChangedEvent is also fired for the first answer
  mySubscription.FireChangedEventForAnswer = true;
  // Start the subscription and as an additional option wait for the first answer as result value
  var FirstAnswerItem = await mySubscription.StartAsync();
  // Change the value of one DPE to trigger the subscription event
  await valueAccess.SetDpValueAsync("ExampleDP_Arg1.", 100.1);
  await mySubscription.StopAsync();
}

6. Erstelle einen Datenpunkt über das ProcessModel

Der folgende Code erstellt einen neuen Datenpunkt “myNewTestDp”. Wenn der Datenpunkt bereits existiert, wird dieser automatisch gelöscht. Führen Sie das Beispiel aus indem Sie den Code in die Program-Klasse kopieren und ModifyDataModelExample().Wait() aus der main()-Funktion aufrufen:.

// SAMPLE 6: Create a data point by using ProcessModel
public async Task ModifyDataModelExample()
{
  // Get access to the ProcessModel
  OaProcessModel dataModel = ManagerInstance.ProcessModel;
  // Check if data point "myNewTestDp" already exists and delete it in that case
  if (await dataModel.IsDpPathExistingAsync("myNewTestDp"))
    await dataModel.DeleteDpAsync("myNewTestDp");
  // Create "myNewTestDp"
  await dataModel.CreateDpAsync("myNewTestDp", "ExampleDP_Float");
}

7. Abfrage der aktuellen Alarme über eine SELECT-Abfrage

Das Beispiel fragt aktuelle Alarme ab. Führen Sie das Beispiel aus indem Sie den Code in die Program-Klasse kopieren und AlertQuerySubscriptionExample().Wait() aus der main()-Funktion aufrufen:.

// SAMPLE 7: Query current alerts using a SELECT statement
EventHandler<OaQuerySubscriptionChangedEventArgs> myAlertChangedEvent = delegate (object sender, OaQuerySubscriptionChangedEventArgs args)
{
  for (int iLoop = 0; iLoop < args.Result.GetRecordCount(); iLoop++)
  {
    var atime = args.Result.GetData(iLoop, 1);
    var avalue = args.Result.GetData(iLoop, 2);
    Console.WriteLine("Record " + iLoop + ": alertTime: " + atime.ToString() + "value: " + avalue.ToString());
  }
};
public async Task AlertQuerySubscriptionExample()
{
  // Get access to Alerts
  var alerts = ManagerInstance.Alerts;
  // Create an AlertQuerySubscription
  var alertSubscription = alerts.CreateAlertQuerySubscription();
  // Configure AlertQuerySubscription;
  // Set AlertChangedEvent by assigning the SystemEventHandler;
  alertSubscription.ValueChanged += myAlertChangedEvent;
  // Trigger a ChangedEvent also for first answer
  alertSubscription.FireChangedEventForAnswer = true;
  // Set the query-string
  alertSubscription.SetQuery("SELECT ALERT '_alert_hdl.._value' FROM '*.**'");
  // start AlertQuerySubscription
  await alertSubscription.StartAsync();
}

8. Historische Werte abfragen

Der Code fragt historische Werte eines spezifischen Zeitbereiches ab. Führen Sie das Beispiel aus indem Sie den Code in die Program-Klasse kopieren und QueryHistoricalValuesExample().Wait() aus der main()-Funktion aufrufen:.

// SAMPLE 8: Query historical values
public async Task QueryHistoricalValuesExample()
{
  // Get access to ValueHistory
  var histAccess = ManagerInstance.ValueHistory;
  DateTime tStart = DateTime.Now; // remember the start time
  // Simulate 5 values using SetValue
  for (int i = 1; i <= 5; i++)
  {
    // using ProcessValues directly without temporary variable
    ManagerInstance.ProcessValues.SetDpValue("ExampleDP_Rpt1.", (double)i);
  }
  DateTime tEnd = DateTime.Now; // remember the end time
  // Query the historical data
  var myResult = await histAccess.GetDpValuePeriodAsync(tStart, tEnd, "ExampleDP_Rpt1.");
  foreach (var TimedValue in myResult)
  {
    Console.WriteLine("Received: " + TimedValue.DpName.ToString() +
                      " Value: " + TimedValue.DpValue.ToString() +
                      " Timestamp: " + TimedValue.SourceTime.ToString());
  }
}

9. Vollständiges Beispiel

Das folgende Beispiel enthält den vollständigen Beispiel-Code:

// SAMPLE 9: Complete sample
public void CompleteSample(string[] args)
{
  // get a local reference to the Manager object
  OaManager myManager = ManagerInstance;
  // Initialize Manager Configuration
  myManager.Init(ManagerSettings.DefaultApiSettings, args);
  // Start the Manager and Connect to the OA project with the given configuration
  myManager.Start();
  // Read from config File Section myCsTest.
  // ReadString(section, key, defaultval)
  OaConfigurationFile file = new OaConfigurationFile();
  string dpNameSet = file.ReadString("myCsTest", "dpNameSet", "ExampleDP_Arg2.");
  string dpNameConnect = file.ReadString("myCsTest", "dpNameConnect", "ExampleDP_Arg1.");
  // Get Access to the ProcessValues
  var valueAccess = myManager.ProcessValues;
  // Create Subscription object
  var mySubscription = valueAccess.CreateDpValueSubscription();
  // Append Datapoints to subcribe on
  mySubscription.AddDp(dpNameConnect);
  // Define Lambda function for value changed event. Can be done as shon here as Lambda function or as seperate function
  mySubscription.SingleValueChanged += (vcsender, vce) =>
  {
    // vce.Value can be null in error case
    if (vce.Value == null)
      return;
    Console.WriteLine("Received value: " + vce.Value.DpValue.ToString() + " for DPE: " + vce.Value.DpName.ToString());
    //Set received value on DPE dpNameSet
    valueAccess.SetDpValue(dpNameSet, vce.Value.DpValue.ToDouble());
    Console.WriteLine("Set value: " + vce.Value.DpValue.ToString() + " also on DPE: " + dpNameSet);
  };
  // If FireChangedEventForAnswer is set to true, the ValueChanged Event is also fired for the first answer
  mySubscription.FireChangedEventForAnswer = true;
  // Start the subscription and as an additional option wait for the first answer as a result value
  mySubscription.StartAsync();
}
  }
}