AFSDK 로 Tag 데이터를 CSV또는 TXT로 내려받기

버전 2

    안녕하세요!

    많은 분들이 AFSDK를 사용하여 Tag 데이터를 CSV파일로 어떻게 대용량으로 내려받는지 궁금해하셨습니다.

    이번 기회에 어떻게 AFSDK를 시작하는지 알아보도록 할게요!

     

    1. 시작

    우선 AFSDK를 C#으로 코딩하기 위해서는 PI AF Client가 설치되어있어야 합니다. PI AF Client가 없다면 이 주소 (https://techsupport.osisoft.com/Downloads/File/182c00a8-6d30-48de-8906-0106fd4a44b0) 로 가셔서 다운을 받고 설치하세요.

    C#코딩을 위해 이번 예제에서는 Visual Studio를 사용하겠습니다. PI AF Client 설치가 완료되었다면 Visual Studio를 실행하시고 프로젝트를 생성하신 후에 AFSDK를 사용하기 위해서는 생성한 프로젝트에 AFSDK를 Reference 시켜야 합니다.

    우선 상단 메뉴에서 Project → Add Reference 를 클릭합니다. 그리고는 Extensions 에서 OSIsoft.AFSDK를 찾아서 클릭을 해줍니다. (영문버전인 점 양해바랍니다.)

     

    1.png2.png

     

    확인을 누르시고 C# 빈 프로젝트를 만드셨으면 이제 Reference로 추가한 AFSDK를 코드에서 사용하기 위해 아래의 코드를 추가해주세요.

    using OSIsoft.AF.PI;
    

     

    자! 그럼 이제 모든 준비가 다 되었습니다. AFSDK로 코딩을 시작해봐요 ^^

     

    2.연결

    우선 Tag를 검색하기 전에 PI Server 로 연결을 해야합니다. PI Data Archive를 연결하는 방법은 많지만, 기본적으로 아래와 같은 코드를 사용하실 수 있습니다.

                PIServers myPIServers = new PIServers();
                PIServer myPIServer = myPIServers["NewPI2016"];
                myPIServer.Connect();
    

     

    여기서 newPI2016은 제가 테스트로 사용한 PI Data Archive의 이름입니다. 이 이름은 String으로 넘어가게 됩니다. 이게 아니라 기본 서버 (Default)로 접속을 원하시면 아래와 같이 쓰셔도 됩니다.

                PIServers myPIServers = new PIServers();
                PIServer myPIServer = myPIServers.DefaultPIServer;
                myPIServer.Connect()
    

     

    3.태그 검색

    PI Tag 리스트를 갖는 오브젝트를 만들어야합니다. Tag의 기본 클래스는 PIPoint가 있으며 이것은 하나의 Point 또는 Tag의 오브젝트를 나타냅니다. 리스트로 가지고 있으려면 IEnumerable<PIPoint> 로 사용이 가능합니다.

    우선 아래코드처럼 PIPoint클래스의 FindPIPoints Method를 사용해보겠습니다.

    IEnumerable<PIPoint> myPIPointList = PIPoint.FindPIPoints(myPIServer, "*s*");
    

    위에 예제는 s가 포함된 모든 Tag를 검색합니다. PIPoint.FindPIPoints method는 여러가지 Override 함수가 있으며 자세한 정보는 AFSDK 도움말을 참조하세요.

     

    4.시간 설정

    myPIPointList를 사용하여 검색된 태그에 대한 데이터를 가져오기 전에, 우선 언제부터 언제까지의 데이터를 가져올지를 설정해야합니다. 데이터를 가져오는 함수에 Time Range 파라미터를 반드시 넘겨야하기 때문에 그 전에 시간을 설정하는 오브젝트를 만들어보겠습니다. AFSDK의 시간 오브젝트를 선언하기 위해서는 OSIsoft.AF.Time namespace를 추가해야합니다. 아래와 같이 추가해주세요.

    using OSIsoft.AF.Time;
    

     

    이렇게 추가함으로서 AFTime Object를 선언 할 수 있습니다. AFTime의 생성자는 여러가지가 있지만 (AFSDK 도움말 참조) 아래와 같이 저희가 익숙한 PI Time Format으로 생성하겠습니다. (*는 현재시간을 의미합니다)

                AFTime startTime = new AFTime("*-1d");  //현재시간으로부터 하루전
                AFTime endTime = new AFTime("*");       //현재시간
    

     

    AF Time range를 아래와 같이 추가할 수도 있습니다.

    AFTimeRange Timerange = new AFTimeRange(startTime, endTime); //총 시간범위는 하루가 된다.
    

     

    5. 데이터 검색

    데이터를 저장하는 클래스는 AFValues 이걸 쓰기위해서는 OSIsoft.AF.Asset Namespace를 추가해야합니다. 아래와 같이 추가해주세요.

    using OSIsoft.AF.Asset;
    

     

    AFValues 는 하나의 PIPoint에 대한 일정한 시간의 값을 저장하는 오브젝트입니다. 따라서 여러개의 PIPoint에 대해서 데이터를 검색하기 위해서는 아래와 같이 foreach문을 사용해야합니다.

                foreach (PIPoint myPoint in myPIPointList)
                {
                    AFValues myValues = myPoint.RecordedValues(Timerange, OSIsoft.AF.Data.AFBoundaryType.Inside, null, false);
                }
    

    PIPoint.RecordedValues의 Parameter에 대해서는 AFSDK 도움말을 참조하세요.

     

    6. 데이터를 CSV로 저장

    이제 foreach문 안에 하나의 Tag에 대해 AFValues를 가져왔습니다. 여기에 저장된 데이터를 텍스트로 저장하기 위해서는 foreach문을 또 추가하여 낱개의 Value를 String 값으로 변환해야합니다. 그리고 동시에 텍스트 파일로 출력도 합니다..아래 코드를 확인하세요.

                    string filePath = "C:\\temp\\" + myPoint.Name + ".csv";
                    File.AppendAllText(filePath, myPoint.Name + Environment.NewLine);    //텍스트파일의 첫 줄에 Tag의 이름을 추가한다.
                    foreach (AFValue myValue in myValues)
                    {
                        File.AppendAllText(filePath,myValue.Value.ToString() + "," + myValue.Timestamp.ToString() + Environment.NewLine); //각각의 행에 태그 값과 시간값을 추가한다
                    }
                     //File Class를 사용하기 위해서는 using System.IO를 추가하셔야합니다.
    

     

    하지만 위의 코드의 경우 데이터의 양이 무지 많을때는 느릴 수가 있습니다. File.AppendAllText 함수는 foreach 구문이 한번 loop 될 때마다 한번씩 File IO를 하게 됩니다. 이럴 경우 속도가 현저히 떨어질 수 있기때문에 프로그래머분들 나름대로 코드를 최적화 시켜주세요.

     

    아래와 같은 코드가 더 효율적일 수 있습니다.

                    int count = 0;
                    string filePath = "C:\\temp\\" + myPoint.Name + ".csv";
                    string output ="";
                    File.AppendAllText(filePath, myPoint.Name + Environment.NewLine);    //텍스트파일의 첫 줄에 Tag의 이름을 추가한다.
            
                    foreach (AFValue myValue in myValues)
                    {
                        count++;
                        output += myValue.Value + "," + myValue.Timestamp + Environment.NewLine; //각각의 행에 태그 값과 시간값을 추가한다
                        if (count % 10000 == 0) //10000개 이벤트가 차면 파일로 내린다.
                        {
                            File.AppendAllText(filePath, output, Encoding.UTF8);
                            output = "";
                        }
                    }
                    File.AppendAllText(filePath, output, Encoding.UTF8);
    

     

    사실 텍스트로 내리는 부분은 고객여러분들의 요구사항에 따라 다르게 수정을 하실 수가 있기때문에 이부분은 자유롭게 바꾸셔도 됩니다.

    전체코드는 본 문서에 첨부가 되어있습니다. 혹시나 코드에 질문이 있으시면 댓글을 달아주세요 ^^

    그럼 즐거운 AFSDK 코딩이 되세요!