niedziela, 13 grudnia 2009

OPC klient z linii poleceń (przykład C# .NET) [PL]

Promuj

Jakiś czas temu zacząłem cykl poświęcony implementacji klienta OPC (Cz. 1. Przygotowania, Cz. 2. Implementacja), w tym post'cie chciałbym wrócić do tematu i przedstawić przykład gotowego programu, który realizuje opisywane możliwiści:

Klient OPC z linii poleceń (OPC command-line client)

Aplikacja ta ma za zadanie odczytywać dane serwera OPC i udostępniać je jako standardowa aplikacja pracująca w "linii poleceń" systemu Windows. Dzięki temu będziemy mogli za pomocą argumentów podawać co chcemy otrzymać, a rezultat zostanie przekazany do standardowego wyjścia, czyli domyślnie na ekran. Załóżmy, że chcemy realizować następujące funkcje:

  • wyświetlanie listy dostępnych elementów
  • wyświetlanie wartości wybranych elementów (razem z jakością i znacznikiem czasowym)
  • wyświetlanie informacji, na temat działania aplikacji

Dodatkowo załóżmy, że aplikacja będzie udostępniała wyniki w postaci tekstu czytelnego dla człowieka oraz w postaci dokumentów XML. Zobaczmy jak może więc wyglądać przykładowa implementacja głównej funkcji (main) takiej aplikacji (Uwaga 1: przykładowy kod został napisany tak aby w najprostszy sposób pokazać implementację opisanej w artykule funkcjonalności i nie powinien być wykorzystany jako dobry przykład implementacji obsługi argumentów linii poleceń. Uwaga 2: Kod zakłada, że dodana została już do solution referencja wskazująca na obiekt serwisu udostępniającego dane z klienta OPC (artykuł: "Implementacja" pokazywał jak należy taką referencję dodać). Uwaga 3: Przykładowe rezultaty działania zakładają, że właściwy klient OPC (DataPorter) jest już odpowiednio zainstalowany, skonfigurowany i uruchomiony (więcej na ten tema pisałem w części poświęconej przygotowaniom)):

static void Main( string[] args )
{
  string commandline = System.Environment.CommandLine;
  if ( commandline.Contains( "--help" ) )
  {
    Console.WriteLine( "Usage:" );
    Console.WriteLine( "OPCClient --help" );
    Console.WriteLine( "OPCClient --list [--xml]" );
    Console.WriteLine( "OPCClient item_names [--xml]" );
    Console.WriteLine( "--help - dispalys this help information" );
    Console.WriteLine( "--xml - enables output as xml" );
    Console.WriteLine( "--list - displays list of items" );
    Console.WriteLine( "item_names - list of item names, that we want to read value separated by spaces " );
    return;
  }
  bool UseXmlOutput = false;
  if ( commandline.Contains( "--xml" ) )
  {
    UseXmlOutput = true;
  }
  //connecting to remote object
  opcDA = new OPCAdvancedDataAccess.OPCAdvancedDataAccess();
  if ( commandline.Contains( "--list" ) )
  {
    GetAvailiableItems( true, UseXmlOutput );
    return;
  }
  //now we can get items values
  //if we are not using the XML output option we can pass arguments array 
  //if we are using XML output, we have to remove --xml from the arguments array;
  if ( UseXmlOutput )
  {
    List list = new List( args );
    list.Remove( "--xml" );
    GetValuesManyItems( list.ToArray(), UseXmlOutput );
  }
  else
  {
    GetValuesManyItems( args, UseXmlOutput );
  }
}

A teraz zobaczmy jak pobierać dane, czyli zaimplementowana jest funkcja GetValuesManyItems:

private static void GetValuesManyItems( string[] ItemNames, bool UseXmlOutput )
{
  OPCAdvancedDataAccess.ItemValue[] values = opcDA.GetValue_MultiItem( ItemNames );
  foreach ( var val in values )
    DisplayOneItemValue( val.ItemName, val, UseXmlOutput );
}
private static void DisplayOneItemValue( string ItemName, OPCAdvancedDataAccess.ItemValue val, bool UseXmlOutput )
{
  if ( UseXmlOutput )
  {
    StringBuilder sb = new StringBuilder();
    StringWriter sw = new StringWriter( sb );
    XmlSerializer serializer = new XmlSerializer( typeof( OPCAdvancedDataAccess.ItemValue ) );
    serializer.Serialize( sw, val );
    Console.WriteLine( sb.ToString() );
  }
  else
  {
    Console.WriteLine( "Item {0}; {1}; {2}; {3}",
      ItemName, val.Value, val.Quality.QualityBits, val.Timestamp );
  }
}

Jak widać wywołuje ona funkcję GetValue_MultiItem wykonywaną przez zdalny obiekt (dostępny przez web service). Funkcja ta zwraca potrzebne wartości (jako ItemValue). Następnie dla każdej otrzymanej wartości wywołujemy funkcję DisplayOneItemValue, która ma za zadanie wyświetlić ją przy użyciu tekstu bądź dokumentu XML. Poniższy rysunek pokazuje efekt przykładowego wykonania opisywanej aplikacji:


Zobaczmy teraz jak pobrać listę dostępnych elementów, czyli jak zaimplementowana została funkcja GetAvailiableItems?:

private static string[] GetAvailiableItems( bool Display, bool UseXmlOutput )
{
  string[] items = opcDA.GetAvailiableItems();
  if ( Display )
  {
    //displaing the list
    if ( UseXmlOutput )
    {
      StringBuilder sb = new StringBuilder();
      StringWriter sw = new StringWriter( sb );
      XmlSerializer serializer = new XmlSerializer( typeof( string[] ) );
      serializer.Serialize( sw, items );
      Console.WriteLine( sb.ToString() );
    }
    else
    {
      foreach ( string item in items )
        Console.WriteLine( item );
    }
  }
  return items;
}

Efekt jej wykonania widać na poniższym rysunku:


W tym przypadku wywoływana jest fukncja GetAvailiableItems zdalnego obiektu, która zwraca listę łańcuchów tekstowych zawierających udostępniane przez serwer i klienta zmienne (tagi).

Mam nadzieję, że w tym krótkim tekście pokazałem, jak można stworzyć prostą aplikację pozyskującą dane z procesu technologicznego poprzez OPC. Proste prawda??

Promuj

1 komentarz:

Posty powiązane / Related posts