Code Examples

The following chapter gives you an introduction into the C# manager API via some executable source code examples. Refer to the last section of this chapter for the complete source code of the example.

  1. Create a new Manager

Follow the instructions of the chapter Create an C# API manager and delete the source code of the class "Program". Your class should now look as follows:

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");
    }
  }
}
  1. Establish a connection

The following example establishes a connection to a WinCC OA project via given program arguments provided by the command line. Copy the source code into your empty project.

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 goes right into the WinCC OA logviewer
      Console.WriteLine("Connection to project established");
      return 1;
    }
  }
}
  1. Read an online value from WinCC OA

First example reads an online value using the synchronous version of the GetDpValue() function from the connected WinCC OA project Run the example by copying the code into the class Program and call ReadValuesExample() from the main() function.

// 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 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());
      }
    }

The second code snippet reads an online value using the asynchronous version of the GetDpValue() function from the connected WinCC OA project. Run the example by copying the code into the class Program and call ReadValuesExampleAsync().Wait() from the main() function.

// 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 a property DpValue from OaDpValue tem
      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;
    }
  1. Write a value to WinCC OA

The following code writes the float value 4.2 on the data point “ExampleDP_Arg1.” Run the example by copying the code into the class Program and call WriteValuesExampleAsync().Wait() from the main() function.

// 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));
    }
  1. Query value changes

The following example subscribes on value and timestamp changes of the data points “ExampleDP_Arg1.” and “ExampleDP_Arg2.”. Run the example by copying the code into the class Program and call SubscribeOnValueChangesExampleAsync().Wait() from the main() function.

 // 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 data points 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();
    }
  1. Create a data point using ProcessModel

The following code creates a new data point “myNewTestDp”. If the data point already exists, it is automatically deleted. Run the example by copying the code into the class Program and call ModifyDataModelExample().Wait() from the main() function.

    // 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");
    }
  1. Query current alerts using a SELECT statement

This code snippet queries current alerts. Run the example by copying the code into the class Program and call AlertQuerySubscriptionExample().Wait() from the main() function.

// 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();
    }
  1. Query historical values

The code queries historical values within a specific time range. Run the example by copying the code into the class Program and call QueryHistoricalValuesExample().Wait() from the main() function.

// 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());
      }
    }
  1. Full example

The following example contains the full example 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 shown here as Lambda function or as separate 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();
    }
  }
}