갑자기 실습이라니!? ㅠㅠㅠㅠㅠㅠ 지금까지 한거라고는 영상보고 액티비티 옮겨보고 실행해보고 한게 전부인데ㅠㅠㅠㅠㅠ 벼락맞은 느낌ㅠㅠㅠㅠㅠㅠ 레벨 2에서는 뭐했는지 기억도 안나!!!!! 도대체 REFramework가 뭐죠?! ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ

이러고 있으니 사수께서 도와주셨다..^^ 우리 능력있는 사수님 짱bb

RoboticEnterpriseFrameworkEx.zip
0.49MB

REFramework 프로젝트를 만들어서 하나하나 뜯어보고 정리 해봤다... 이거 말고도 손으로도 직접 필기하면서 공부해보니까 이해가 빡 됐다! ^^b

 


 

UIDemo Walkthrough.pdf
0.60MB

 

이거만 보고서 따라했더니 실행이 되었다... 처음 REFramwork로 프로그램을 짜보니까 재밌었음. 이번 실습을 통해서 어떻게 사용해야할지 감을 잡을 수 있었음.. 딱히 어려운건 없었던 느낌..

너무 모르겠다면 유튜브에 workthrough 영상이 참~ 많이 있는데 참고만 하면 좋을 것 같다

나 같은 경우는 어떻게 참고 했냐면, 영상 맨 마지막에 Run 해서 어떻게 프로그램이 돌아가는지 영상으로 확인하니까 내가 뭘 만들어야할지 감이 잡혀서 REFramework의 4단계(INIT, GTD, PROCESS, EP)를 그려놓고 어떤 프로세스가 어디에 들어가야할지 적었다. 그리고 나서 플로우를 직접 만들고, 문제가 있으면 왜그럴까 생각도해보고, 에러도 해석해서 고쳐보고, 내가 뭘 잘못했고 어떻게 고치면 되는지 생각해보는 과정들이 짜릿했다ㅎㅋ 나중에 프로그램이 잘 돌아가면 보람이 엄청 엄청 느껴졌당 ㅎㅎ 이렇게 처음부터 공부하면 시간이 너무 오래걸리지 않을까... 걱정했지만 하루 안에 끝났다ㅠㅠㅠ 하긴 내가 아는것도 없는데 처음부터 다 뜯어봐야 나중에 편하지ㅠㅠㅠㅠ

무턱대고 처음부터 유튜브에서 하라는대로 따라했다가 나중에 에러가 나면 진짜 대략난감... 처음부터 보고 따라하겠다고 시작하면 나중에 에러가 나도 어떻게 해봐야할까! 의지도 안생기고 그냥 왜 에러가 나는거야ㅠㅠ 짜증만 내고 에러문만 구글링하고 있는 내 자신을 발견함... 정말 개발자로서 무서운 일이다.... 유튜브는 참고용이지 보고서 따라하면 실력이 절대 늘지 않을 것 같아...

 

UiPath_REFrameWork_UiDemo.zip
0.63MB

 

 

 

** 해야 할 일

1. select from DB => show Android ()

2. input Android => insert data to DB

 


** use DataBase : MySQL

** Setting ("xampp\htdocts" 에서 php 파일 보관)

use DataBase(DBMS) MySQL(PHPMyAdmin) Environment Windows10
web Server Apatch(localhost, 개이IP) etc 통합 환경 XAMPP 사용

 

여러번 삽질을 해본 결과... 사실 연동이라 함은 깔끔하게 데이터만 뽑아서 가져올법 하지만, 그건 모두 개발자의 몫이다.. 따라서 원하는 데이터가 있다면 먼저 DB에서 php 화면에 데이터를 불러와서 띄운다음에, 그 띄운 글자를 안드로이드에 배열 형태로 가져온다. 그리고 배열에서 '[' 같은 문자를 파싱하고 출력하면 내가 처음에 원하는 것이 나온다...

주로 이런 값 전달은 phpecho "전달할값"$변수명 으로 통한다. 안드로이드에서 쓴 글씨를 DB에 넣지 않고 php 상에서 본다는건... 사실상 좀 까다로운 일 같다.., 될 수 있는지도 모르겠다..

"안드로이드에서 받은 값을 DB에서 넣지 않고 php 상에 띄운다""안드로이드에서 입력한 값을 php로 보내서 echo로 출력하면 그 출력 데이터가 다시 돌아와 안드로이드에서 출력된다" 와 같은 의미였다... 하긴, 동적인 값을 어떻게 php에서 받아서 바로바로 출력해줄 수 있겠어...

 

** 1. select from DB => show Android

1) Select from DB - PHP

안드로이드에서 DB의 값을 출력하고싶다면, 먼저 DB에서 값을 가져와 PHP에 출력하는 작업이 필요하다. 사실상 출력이라기보다는 값전달에 가깝다. PHP 화면상에 DB의 값이 출력되는건 echo 함수로 값을 전달 할 수 밖에 없기 때문에 보여질 수 밖에 없는 것이다..

다음은 DB에서 값을 읽어와 php에 출력하는 코드.

- insertData.php

<?php
    // DB 연동을 시작합니다.
    $con=mysqli_connect("호스트명", "DB ID", "DB PW", "DB 이름");

    // mysqli_connect()에 대한 마지막 호출에 대한 오류 코드 값을 반환한다.
    // echo mysqli_connect() 에서 0은 오류가 발생하지 않았음을 의미한다
    if (mysqli_connect_errno($con)) {
        echo "Failed to connect to MySQL: " . mysqli_connect_error();
    }


    /* select data */
    // 1. 실행할 쿼리문을 작성합니다.
    $selectSQL = "select * from ttest";
    $result = mysqli_query($con, $selectSQL);

    // 출력할 데이터를 저장할 배열변수 선언
    // 데이터는 json-array 형식으로 출력할 것임 (일반적으로 이렇게 함)
    $data = array();
    
    if ($result) {
        while ($row=mysqli_fetch_array($result)) {
            array_push($data,array('컬럼명'=>$row[0],'컬럼명'=>$row[1]));
        }
        header('Content-Type: application/json; charset=utf8');
        $json = json_encode(array("테이블이름"=>$data), JSON_PRETTY_PRINT+JSON_UNESCAPED_UNICODE);

		echo $json; // => 출력되는 값이 이 코드로 하여금 android로 전송된다..

	} else {
        echo "SQL문 처리중 에러 발생 : ";
        echo mysqli_error($con);
    }

    // DB 연동을 종료 합니다
    mysqli_close($con);
?>

여기서, if 문을 살펴보자

array_push($data,array('컬럼명'=>$row[0],'컬럼명'=>$row[1]));

배열로 선언한 data 변수에 첫번째 컬럼명(row[0]), 두번째 컬럼명(row[1]) 을 연관배열의 형태로 저장한다. 이 부분은 필요하다면 for을 사용해서 더 깔끔하게 코딩할 수 있다.. 나는 그냥 필요한 만큼만 했다.. 여기서 '컬럼명'은 연관배열로 지정해줄 이름일뿐, 굳이 컬럼명을 적지 않아도 된다!!! 대신 컬럼명이 아닌데 컬럼 값을 가지고 있으면, 다른 사람이 볼 때 어떤 값인지.. 잘 알아볼 수 있을까..ㅎ

$json = json_encode(array("테이블이름"=>$data), JSON_PRETTY_PRINT+JSON_UNESCAPED_UNICODE); 

json이라는 변수를 선언하고 아까 data 배열 변수를 json 코드로 인코딩해서 저장했다. 뒤에 있는건 추가적으로 json 배열이 더 예쁘게 내보이고 싶다면 사용하는 옵션이다. 더 필요한 옵션이 있다면 구글링을 하시도록!

 

2) Show Android - Android Programming

- activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:layout_margin="40dp"
    android:gravity="center"
    tools:context=".MainActivity">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <EditText
            android:id="@+id/edtText1"
            android:hint="ID"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
        <EditText
            android:id="@+id/edtText2"
            android:hint="PW"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
        <LinearLayout
            android:gravity="center"
            android:layout_marginTop="20dp"
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <Button
                android:id="@+id/insertBtn"
                android:text="insert"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
        </LinearLayout>
    </LinearLayout>
    <LinearLayout
        android:orientation="vertical"
        android:layout_marginTop="80dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/txtView"
            android:text="test txt"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    </LinearLayout>
</LinearLayout>

 

- MainActivity.java

public class MainActivity extends AppCompatActivity {

    private TextView txtView;
    private EditText editText1, editText2;
    Button insertBtn;

    private static String IP = ""; //서버 없이 사용하는 IP가 있다면 저장해서 사용하면 된다.

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

		// 사용할 액티비티 선언
        editText1 = findViewById(R.id.edtText1);
        editText2 = findViewById(R.id.edtText2);
        insertBtn = findViewById(R.id.insertBtn);

		// String url = "http://" + IP + "/php파일명.php";
        String url = "http://" + IP + "/InsertData.php";
        selectDatabase selectDatabase = new selectDatabase(url, null);
        selectDatabase.execute(); // AsyncTask는 .excute()로 실행된다.

    }


    class selectDatabase extends AsyncTask<Void, Void, String> {

        private String url1;
        private ContentValues values1;
        String result1; // 요청 결과를 저장할 변수.

        public selectDatabase(String url, ContentValues contentValues) {
            this.url1 = url;
            this.values1 = contentValues;
        }
        
        @Override
        protected String doInBackground(Void... params) {
            RequestHttpURLConnection requestHttpURLConnection = new RequestHttpURLConnection();
            result1 = requestHttpURLConnection.request(url1, values1); // 해당 URL로 부터 결과물을 얻어온다.
            return result1; // 여기서 당장 실행 X, onPostExcute에서 실행
        }
        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            //txtView.setText(s); // 파서 없이 전체 출력
            doJSONParser(s); // 파서로 전체 출력
        }
    }

	// 받아온 json 데이터를 파싱합니다..
    public void doJSONParser(String string) {
        try {
            String result = "";
            JSONObject jsonObject = new JSONObject(string);
            JSONArray jsonArray = jsonObject.getJSONArray("ttest");

            for (int i=0; i < jsonArray.length(); i++) {
                JSONObject output = jsonArray.getJSONObject(i);
                result += output.getString("ed1txt")
                        + " / "
                        + output.getString("ed2txt")
                        + "\n";
            }

            txtView = findViewById(R.id.txtView);
            txtView.setText(result);

        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

}

 

- RequestHttpURLConnection.java

public class RequestHttpURLConnection {

        public String request(String _url, ContentValues _params){

            // HttpURLConnection 참조 변수.
            HttpURLConnection urlConn = null;
            // URL 뒤에 붙여서 보낼 파라미터.
            StringBuffer sbParams = new StringBuffer();

            /**
             * 1. StringBuffer에 파라미터 연결
             * */
            // 보낼 데이터가 없으면 파라미터를 비운다.
            if (_params == null)
                sbParams.append("");
                // 보낼 데이터가 있으면 파라미터를 채운다.
            else {
                // 파라미터가 2개 이상이면 파라미터 연결에 &가 필요하므로 스위칭할 변수 생성.
                boolean isAnd = false;
                // 파라미터 키와 값.
                String key;
                String value;

                for(Map.Entry<String, Object> parameter : _params.valueSet()){
                    key = parameter.getKey();
                    value = parameter.getValue().toString();

                    // 파라미터가 두개 이상일때, 파라미터 사이에 &를 붙인다.
                    if (isAnd)
                        sbParams.append("&");

                    sbParams.append(key).append("=").append(value);

                    // 파라미터가 2개 이상이면 isAnd를 true로 바꾸고 다음 루프부터 &를 붙인다.
                    if (!isAnd)
                        if (_params.size() >= 2)
                            isAnd = true;
                }
            }

            /**
             * 2. HttpURLConnection을 통해 web의 데이터를 가져온다.
             * */
            try{
                URL url = new URL(_url);
                urlConn = (HttpURLConnection) url.openConnection();

                // [2-1]. urlConn 설정.
                urlConn.setRequestMethod("POST"); // URL 요청에 대한 메소드 설정 : POST.
                urlConn.setRequestProperty("Accept-Charset", "UTF-8"); // Accept-Charset 설정.
                urlConn.setRequestProperty("Context_Type", "application/x-www-form-urlencoded;cahrset=UTF-8");

                // [2-2]. parameter 전달 및 데이터 읽어오기.
                String strParams = sbParams.toString(); //sbParams에 정리한 파라미터들을 스트링으로 저장. 예)id=id1&pw=123;
                OutputStream os = urlConn.getOutputStream();
                os.write(strParams.getBytes("UTF-8")); // 출력 스트림에 출력.
                os.flush(); // 출력 스트림을 플러시(비운다)하고 버퍼링 된 모든 출력 바이트를 강제 실행.
                os.close(); // 출력 스트림을 닫고 모든 시스템 자원을 해제.

                // [2-3]. 연결 요청 확인.
                // 실패 시 null을 리턴하고 메서드를 종료.
                if (urlConn.getResponseCode() != HttpURLConnection.HTTP_OK)
                    return null;

                // [2-4]. 읽어온 결과물 리턴.
                // 요청한 URL의 출력물을 BufferedReader로 받는다.
                BufferedReader reader = new BufferedReader(new InputStreamReader(urlConn.getInputStream(), "UTF-8"));

                // 출력물의 라인과 그 합에 대한 변수.
                String line;
                String page = "";

                // 라인을 받아와 합친다.
                while ((line = reader.readLine()) != null){
                    page += line;
                }

                return page;

            } catch (MalformedURLException e) { // for URL.
                e.printStackTrace();
            } catch (IOException e) { // for openConnection().
                e.printStackTrace();
            } finally {
                if (urlConn != null)
                    urlConn.disconnect();
            }

            return null;
        }
}

 

- NetworkTask.java

public class NetworkTask extends AsyncTask<Void, Void, String> {

        private String url;
        private ContentValues values;

        public NetworkTask(String url, ContentValues values) {

            this.url = url;
            this.values = values;
        }

        @Override
        protected String doInBackground(Void... params) {

            String result; // 요청 결과를 저장할 변수.
            RequestHttpURLConnection requestHttpURLConnection = new RequestHttpURLConnection();
            result = requestHttpURLConnection.request(url, values); // 해당 URL로 부터 결과물을 얻어온다.

            return result;
        }

}

insert도 비슷하니까 설명 생략하고 그냥 코드 복붙..

 

** 2. input Android => insert data to DB

1) Type input data - Android

- insertData.php (코드 추가함)

<?php

/* insert data */
    // 1. 안드로이드에서 post로 날린 값을 받아 변수에 저장합니다
    $ed1txt = $_POST['ed1txt'];
    $ed2txt = $_POST['ed2txt'];

    // 2. 실행할 쿼리문을 작성합니다. => mysqli_query(실행할 Db, 실행할 query)
    $insertSQL = "insert into ttest (ed1txt,ed2txt) values ('$ed1txt','$ed2txt')";
    $result1 = mysqli_query($con, $insertSQL);

    if ($result1) {
        echo "Success!!";
    } else {
        echo "Fail insert data to Database...";
    }
    
    ?>

 

2) Insert data to DB - PHP

- MainActivity.java (코드 추가함)

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        insertBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                insertoToDatabase(editText1.getText().toString(),editText2.getText().toString());
            }
        });

    }

    private void insertoToDatabase(final String ed1, String ed2) {
        class InsertData extends AsyncTask<String, Void, String> {
            ProgressDialog loading;

            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                loading = ProgressDialog.show(MainActivity.this, "Please Wait", null, true, true);
            }
            @Override
            protected void onPostExecute(String s) {
                super.onPostExecute(s);
                loading.dismiss();
                //Log.d("Tag : ", s); // php에서 가져온 값을 최종 출력함
                Toast.makeText(getApplicationContext(), s, Toast.LENGTH_LONG).show();
            }
            @Override
            protected String doInBackground(String... params) {

                try {
                    String edt1Text = (String) params[0];
                    String edt2Text = (String) params[1];

                    String link = "http://"+cafeIP+"/InsertData.php";
                    String data = URLEncoder.encode("ed1txt", "UTF-8") + "=" + URLEncoder.encode(edt1Text, "UTF-8");
                    data += "&" + URLEncoder.encode("ed2txt", "UTF-8") + "=" + URLEncoder.encode(edt2Text, "UTF-8");

                    URL url = new URL(link);
                    URLConnection conn = url.openConnection();

                    conn.setDoOutput(true);
                    OutputStreamWriter outputStreamWriter = new OutputStreamWriter(conn.getOutputStream());
                    outputStreamWriter.write(data);
                    outputStreamWriter.flush();

                    BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));

                    StringBuilder sb = new StringBuilder();
                    String line = null;

                    // Read Server Response
                    while ((line = reader.readLine()) != null) {
                        sb.append(line);
                        break;
                    }
                    Log.d("tag : ", sb.toString()); // php에서 결과값을 리턴
                    return sb.toString();

                } catch (Exception e) {
                    return new String("Exception: " + e.getMessage());
                }
            }
        }
        InsertData task = new InsertData();
        task.execute(ed1,ed2);
    }

 

 


** 헉 대박 이거 잊으면 안됨 꼭 해야함

** manifest 셋팅

- AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapplication">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:usesCleartextTraffic="true">
    </application>

</manifest>

 

1. 인터넷 퍼미션

2. thread 오류가 나도 계속 진행하게함.

 


 

 

200211 UIPath study


- Level 3 Robotic Enterprise Framwork




** Building productive Robot requires

- 적절한 예외 처리

- 복구 기능

- 효과적인 로킹 및 리포트 기능

- 유지 관리 용이성

- 확장성

- 재활용 가능성

- 개발 편의성


** REFramework (전반적인 흐름)

- plug and play 방식 : 일련의 파일, 일부는 변경, 매개변수화 / 일부는 변경없이 그대로 사용 함

- Main.xsml : Orchestrator에서 프로젝트를 배포하고 시작하면 실행되는 파일

- StateMachine 도식을 사용하여 4가지 단계를 가진다.

: Init, Get Transaction Data, Process Transaction, End Process

1) Init State : 로봇이 구성을 읽고 어플리케이션을 초기화 하는 과정

2) Get Transaction Data : Init State가 성공 시 반환하는 과정

(1) 로봇을 통해 새 트랜젝션이 처리 ▶ Process Transaction 과정으로 넘어감

(2) 모든 트랜젝션이 이미 수행 ▶ 더 이상 데이터가 남아 있지 않을 경우 프로세스 종료

3) Process Transaction : 3가지의 결과가 도출됨

(1) Success : loop를 수행하고 다음 트렌젝션 데이터를 가져옴

(2) Business rule exception : 몇 가지 특정 수행 과정이 있어야함. 그 후에는 다시 Get Transaction Data 단계로 돌아감

(3) System Error Transaction : 사용자가 필요한 조취를 취해 오류를 복구해야함. 이에 따라 모든 어플리케이션이 종료되고 Init 단계로 돌아가 어플리케이션이 재시작함

4) End Process : Init State에서 시스템 오류가 발생할 경우 반환하는 과정, 


** Init State

- 로봇이 Setting을 읽고 필요한 모든 어플리케이션을 시작함.

- 전반적인 예외 처리 구현, 따라서 모든 액티비티에 try-catch 액티비티가 있음

- 로봇은 초기화를 시도하며, 초기화가 실패할 경우 프로세스가 종료됨

- 예외가 발생했는지 확인하기 위해 예외 객체로 SystemError를 설정 = "Nothing"

- 다음으로 Config 파일을 읽은 후 모든 어플리케이션을 시작함

- SystemError 값에 따라 Get Transaction Data 혹은 End Process 로 이동함

- SystemError 값이 "Nothing"이면, Get Transaction Data 를 진행함

- 시스템 예외가 발생할 경우 초기화가 실패했다는 Fetal 오류 메세지가 표시되고 로봇이 End Process로 진행함.

(1) Reading Config File

- condition = "Config is Nothing"

- Config : Dictionary/key:String/value:Object

(2) Setting sheet

- 해당 비지니스 프로세스와 관련된 모든 구성을 저장할 수 있음.

- 큐이름, URL, 파일경로, 자격증명이름, 기타 모든 프로세스와 관련된 정보

- Excel column : Name(string, Dictionary's key) / Value( / Dictionary's value) / Description(setting 설명)

(3) Constants sheet

- 유용한 기술적 설정이 저장됨. 프로젝트 세부 사항을 조정하고, 성능을 개선하며, 쉽게 환경을 전환할 수 있음. (개발환경▶테스트환경▶운영환경)

- 재시도 횟수, 제한 시간, 지연 시간, 이미지 정확도 설정, 정적 로그 메세지 등

- 프로젝트에서 제한 시간, 지연 시간을 하드코딩 하는 대신에 Config 객체를 사용하면 값을 전역적으로 쉽게 조정할 수 있음.

- MaxRetryNumber : 어플리케이션 예외나 시스템 오류로 인한 실패로 트랜잭션을 재시도하는데 사용함. Config 파일의 기본 값은 0, 재시도 횟수는 Orchestrator에서 설정됨.

(4) KillAllProcess

- 로봇이 정리되고 적절히 제어되는 환경에서 시작되도록 시작 부분에서 수행됨.

(5) 모든 어플리케이션을 실행함

- 프로세스에서 사용되는 어플리케이션에 따라 xaml 파일을 매개변수화 해야 함.


** Get Transaction Data

- 프로세스의 트랜잭션을 완료하는데 필요한 데이터를 가져오는 매커니즘

- 트랜잭션 : 프로세스에서 반복되는 부분

- TransactionNumber : 트랜잭션을 실행할 때마다 번호가 매겨지는데 이 값이 저장됨. (기본값:1)

- TransactionItem : OueueItem형식, 하지만 필요에 따라서 변경할 수 있다

(1) Orchestrator에서 Stop 신호를 보냈는지 확인함

(2) 보낸 경우 End Process 단계로 이동해 로봇을 정상적으로 중지함

(3) Stop 명령을 받지 않은 경우, GetTransactionData 파일을 호출함.

(in:TransactionNumber, ConfigDictionary / out:TransactionItem)


** End Process

- 모든 어플리케이션을 닫으려고 시도하고, 실패하면 KillAllProcesses를 호출하는 방식




200211 UIPath Study

- 오케스트레이터 트레이닝 비디오 생각보다 친절하지 않았다 ㅡㅡ




** 연결 방법 (순차대로 진행해야함 ㅠ 안그럼 꼬임)


1. UIPath flatform 에서 Service를 만들고 접속


2. 접속하면 그 페이지가 Orchestrator 페이지


3. 좌측 네비게이션 Management 에서 초기 작업


4. Machines에서 사용할 PC 등록
- 대부분 Standard machine으로 등록
- Name: (머신이름, 마음대로 지어도 됨)
- Description : (머신에 대한 설명)


5. Robots에서 Robots 등록
- 보통 Standard robot 으로 생성. 단, standard robot은 machine 당 1개만 생성할 수 있음.
- Machine : (4단계에서 만든 machine이 드롭다운에 뜸.)
- Name: (머신이름, 마음대로 지어도 됨)
- Type: (특별한거 없으면 Studio)
- Domain\Username: (C:\Users\PC이름)
- Password : (사용하는 머신의 비밀번호, 노트북 비밀번호, 부팅할때 치고 들어오는^^)
- Description : (머신에 대한 설명)


6. Robots의 상단에 보면 Environments 라고 있음. 거기서 환경 생성. 
- 환경을 생성하면, 머신을 설정할 수 있도록 되어있음. 5번에서 생성한 로봇을 설정함.
- Name: (환경이름, 마음대로 지어도 됨)
- Description: (환경에 대한 설명)


7. Orchestrator에서 나와서 Robots 프로그램을 실행. Orchestrator Settings에 들어감
- Orchestrator URL: (https://platform.uipath.com/hanyapmmbbzq/1번에서 만든 서비스명까지)
- Machine Key: (4단계에서 만들었던 Machines에 생성했던 머신에서 더보기란(...) 에서 Edits을 누르면 Machine Key가 있음. 복붙하면 됨)
- Connection


8. UIPath Studio에서 프로젝트를 Publish함 (Main.xaml에서 작업해야함. 특별한 설정 없으면ok,ok)


9. Orchestrator에서 좌측 메뉴의 하단 Management의 Package에 보면 프로젝트가 업데이트 되어있음.


10. Automation의 Processes에 들어가면 publish한 프로젝트가 있음. 더보기란(...)에 View Process로 들어가면 프로젝트의 업데이트 항목이 나와있고, LATEST를 누르면 최신 버전의 업데이트, ROLLBACK 하면 이전 버전으로 다운데이트함.



200210 UIPath study

- 12, 13, level test 진행 
- Level 1 Done~ 예ㅔ~




** try-catch-finally 예외처리
- try : 첫번째로 실해할 flow
- catch : try문에서 error가 있을 때, 실행할 flow, 반복 실행 flow를 짤 수 있다.
- finally : 예외의 유무와 상관없이 반드시 실행되는 flow


** 예외의 종류
- IOException : 입출력에 error가 있을 때 발생
- NullReferenceException : 설정 값이 없는 변수를 사용할 때 발생
- IndexOutOfRangeException : 입력한 인덱스가 컬렉션의 제한을 벗어 났을 때 발생
- ArgumentException : 전달된 인수 중 적어도 하나가 호출된 메소드의 매개 변수 스펙을 충족하지 않는 경우 발생
- SelectorNotFoundException : 기간 내에 대상 앱에서 활동에 대해 지정된 선택기를 찾을 수 없을 때 발생
- ImageOperationException/TextNotFoundException : 기간 내에 이미지 / 텍스트를 찾을 수 없을 때 발생
- ApplicationException : 응답하지 않는 응용 프로그램과 같은 기술적 인 문제에 기인하여 발생


** 예외 처리와 관련된 activity
- Rethrow : 예외처리를 던지고 종료함 (catch문은 반복 flow를 짤 수 있기 때문에 강제종료와 비슷함)
- Extract as Workflow : try문과 catch문에 반복되는 flow를 따로 파일로 저장해서 불러올 수 있다.
- invoke workflow로 파일을 불러옵니다


** invoke
- 독립적인 파일을 관리해 flow를 깔끔하게 짤 수 있도록 도와줌
- 파일 간의 값을 전달하려면 인수(argument)를 사용해야한다.


** 방향
- in : 값이 들어오기만 할 수 있다
- out : 값이 나가기만 할 수 있다.
- in/out : 값이 들어왔다가 (필요하면 값의 계산 후)
 나갈 수 있다.


** Best Practices
- Pick an appropriate layout for each workflow
- Break the whole process in smaller workflows
- Use exception handling
- Make you workflows readable
- Keep it clean





Level1_Ex14.xaml
0.03MB
Level1_Ex15.xaml
0.03MB
Level1_Ex16.xaml
0.03MB
Lesson12 Practice.xaml
0.01MB
Lesson13 Practice1.xaml
0.01MB


200207 UIPath study

- 8, 9, 10 까지 진행




** citrix recordinf : find IMG
- find imgae 액티비티로 drag해서 찾은 이미지를 변수에 넣어야한다면, 데이터 타입은 UIElement
- find image를 통해서 찾은 이미지로 페이지를 식별할 수 있다. 단, 가상환경에서 find image를 한 경우, 변동이 있을 수 있는 이미지를 선택하는 것이 아니라 항상 같은 이미지와 같은 장소에 있는 이미지를 선택해야한다. 예를 들어서, 탭 부분에 있는 회사의 로고라던지..!


** Selector
- anchor base 혹은 relative selector로 selector를 설정해줄때, type into나 click과 같은 액티비티를 설정해야하는데 위치가 변동이 없을 경우에는 정적 Selector를 사용한다. 위치가 가변적일 때는 동적 Selector를 사용하면 좋다.


** citrix recordinf
- 가상 환경에서의 액티비티 조작은 까다로울 수 있기 때문에 다음과 같은 방법으로 접근한다.
- 바탕화면에서 app을 조작할 때 다음과 같은 방법으로 접근할 수 있다. 상황에 맞춰서 사용하면 좋을 듯 하다.
1) find IMG
- 바탕화면에 있는 아이콘의 img를 drag 하여 인식하게 한다.
- 하지만, 이 경우는 부주의한 경우일 수 있다. drag 한 img에 바탕화면 색깔이 섞여 다른 바탕화면으로 전환했을때 인식할 수 없던지, 혹은 icon 위에 다른 식별표시가 겹치면 확인하지 못할 수 있다.
2) Set short cut key
- 바탕화면에 있는 app의 단축키를 설정한다.
- 기존의 단축키와 겹치게 되면 문제가 되지만, 그렇지 않고 복잡한 단축키를 사용하면 오히려 더 정확한 방법이 될 수 있다.
- send hot key 액티비티를 사용해 단축키를 지정해서 app을 열 수 있다.
3) DOS
- 가상 환경에서 DOS를 열어 app 파일의 경로를 지정한다.
- app 파일의 경로는 변수에 저장하며, 가상환경에서 DOS 창을 여는 flow도 PC 환경에 맞게 구성해야한다.
- 아니면 win+R 단축키로 실행창을 열어서 app 파일의 경로를 type into 한다.


** Excel Application Scope (Properties)
- CSV 파일과는 다르게 엑셀 데이터를 다룰 때 필수 입니다.
- 여러가지 속성과 액티비티가 있는데, 속성과 액티비티 개념을 잘 살펴보면 쉽게 사용할 수 있습니다.
- Excel/Workbook 명을 표시하는 상단에는 파일 이름을 적습니다. Read->현존하는 파일명을 기입하고, write->새로운 파일명을 기입하고 폴더 내에 동일한 엑셀 파일이 없다면 새로 만들어 줍니다. 
- Visible : 체크하면 눈에 보이게 실행(Excel 설치 필수), 체크 안하면 백그라운드 실행(Excel sw 없어도됨)

- output data Table 액티비티 : 콘텐츠를 output 패널에 출력하는 것이 아니라 적절히 표시할 수 있는 문자열로만 변환합니다.


** Excel/Workbooks VS DataTables
- Excel/Workbooks : 엑셀 파일을 가리키는 말로 모든 유형의 데이터, 서식, 시트, 레이아웃, 병합된 셀과 여러 데이터 테이블을 가질 수 있다.
- Data Tables : 가장 단순한 유형의 스프테드시트 타입으로 행과 컬럼, 선택적으로 머리글만 가질 수 있다.


** 다양한 Excel data 활용 activity
- Read range/row
- write range/row
- Bulid data table
- Append range/row
- Filter Data Table
- Output Data Table

- for each row, while 로 row data를 읽을 수 있음. 
- for each row : Get Row Item(Colum/Row/Value Properties 필수), Add Data Row


** PDF
- pdf 파일에서 정보를 읽어오기 전에 파일 내의 data를 마우스 커서로 긁어보면서 이미지인지 텍스트인지 확인해야합니다
- 텍스트틑 쉽게 선택되지만, 이미지는 블록 형태로 선택됩니다.
- 전체 파일을 읽어올 경우 VS 특정 정보만 읽어올 경우


** Read PDF (with OCR) Properties
- 많은 양의 텍스트를 읽어올 때 사용함. 페이지를 읽고 문자열 변수를 출력한다.
- range : "all" -> 전체
"2" -> 2페이지만
"3-7" -> 3~7페이지만
- 독립형 어플리케이션이기 때문에 둘 다 백그라운드에서 작동할 수 있다.
- OCR에서 글씨를 잘 못읽어 올 수 있기 때문에 OCR을 사용하는 것 보다는 Read PDF를 사용해서 읽어오는걸 더 추천한다.
- 전체 데이터를 읽어오지 않는 경우에는 screen scrapping 을 사용한다. 제일 빠른 방법
 

** Read PDF file using Anchor Base
- get partial data
- Anchor Base (Find Element, Find Image)
- pdf의 경우 문서 내의 이미지가 변하지 않고 동일한 형식의 데이터를 가지고 있기 때문에 일반적으로 우려되는 find image의 에러 없이 사용할 수 있습니다.


Lesson9 Practice.xaml
0.01MB
Level1_Ex10.xaml
0.04MB
Level1_Ex11.xaml
0.03MB
Level1_Ex12.xaml
0.03MB
Level1_Ex13.xaml
0.02MB

 

 


200206 UIPath study


- Lesson 5, 6, 7 까지 진행
- Citrix Recording 방법(미숙지)
- data scaping으로 CSV/Excel file 생성
- 다양한 Seletor 구현(Anchor, Relative Selector)
- recording이 아닌 수동으로 로직 생성

- 금요일까지 진도를 최대한 빼보고 다음주 플랜 짜기
- 2/21 까지 level 3 끝내기~





** Selector

모든 사용자 interface는 컨테이너의 요소를 사용해 만들어지며, 대게 컨테이너 안에 또 다른 컨테이너가 있습니다. UIPath는 이런 컨테이너와 요소의 다양한 속성을 사용해 올바른 요소에 대한 전체 경로를 찾습니다. 경우에 따라 속성은 동적이므로 wild card를 사용해 동적 부분을 무시하거나 매우 유용한 기능인 Attach to live Element를 사용해 자동으로 구현할 수 있습니다. 또한 Selector 내에서 변수를 사용하는 방법과 목록에서 N번째 요소를 인덱스 속성을 사용해 선택하는 방법을 알아봤고, 이는 Selector의 안정성이 높지 않음을 나타냅니다. 

(1) full selector
- UI 구성 요소를 찾는 데 필요한 모든 요소를 포함하고 있다.
- 최상위 요소를 포함하지 않으며(전체 Selector에 최상위 요소가 없는 Selector) 컨테이너 안에 들어있어 컨테이너는 attach window 또는 open applicarion와 같은 컨텍스트를 지원한다.
- 다른 어플리케이션과 창이 서로 방해할 수 있는 경우에 사용한다..
(3) 동적 Selector
- 요소 자체가 시간에 따라 변하고 고정되어 있지 않을때 사용한다. 와일드 카드(*, ?) 사용. 파일의 명, URL이 변할 수 있기 때문에, 와일드 카드를 이용하여 동적 Selector를 구현합니다.
- Selector로 어플리케이션을 인식할 때 title을 수정하는데, *를 해당 주소의 앞뒤에 기입한다
- 주소와 상관없이 모든 어플리케이션을 인식할때는 title에 *만 기입한다.
- Selector 값에 변수를 추가해주면서 매개변수의 역할을 하게 할 수 있습니다. 단, Selector 내부의 element 속성 변경은 UI Exploer에서 작업합니다


** wild card
- * : 임의의 문자 수
- ? : 단일 문자


** Set Name : 변수명 -> 자동변수 생성


** RPA challenge
- Anchor Base 또는 Relative Selector 를 통해 임의의 위치에 있는 element를 찾아낼 수 있다.
- Anchor Base 는 화면상에서 가시적으로 작동하지만, 백그라운드에서 작동이 안됩니다.
- Relative Selector는 백그라운드에서 작업이 가능하지만, 어플리케이션의 내부 구조에 의존해서 작동이 되기 때문에 Selector 설정을 해야합니다. 직접 Selector를 Edit 해서 구현합니다. UI Exploer에서 속성을 변경합니다. ID 값이나 Name 값과 같은 고정된 값을 가지는 element는 사용하지 않습니다.


** Cirtix Recording
- 가상머신은 서버에서 실행되며 인터페이스의 이미지만 사용자에게 전달. 따라서 UIPath가 운영체제를 사용자의 이미지를 처리해줄 수 없다. 





Level1_Ex08.xaml
0.02MB
Level1_Ex09.xaml
0.03MB
Lesson5 Practice.xaml
0.01MB
Lesson6 Practice.xaml
0.04MB

 

 

 



200205  UIPath study


- lesson 4까지 마무리 했음
- 레코딩, 데이터테이블, 반복문, 제어흐름 등
- 실습 과제 없이 아카데미와 QnA로 진행
- 변수의 사용
- 여러가지 새로운 액티비티를 경험함
- 레코딩 기능 없이 직접 RPA를 구현함






** 좋은 로직
- RPA도 기능 별로 먼저 세분화 한 뒤에 분업
- sequence는 선형 플로우기 때문에 처음으로 돌아가서 반복하는 플로우를 짜는 것은 지양한다. 그렇게 반복을 해야하는 경우는 while문을 이용하면 된다.


** loop(반복문)
- 루프는 반복적인 작업을 자동화하는데 가장 흔히 사용되는 구조. 비슷한 작업을 반복하여 자동화하는 일반 프로그래밍의 핵!심!기!능!!
- flow chart : 특정 지점을 이전 실행 지점에 연결하여 간단하게 구현할 수 있음
- sequence : looping container가 Body section 내부에서 action을 반복함.

** loop in sequence
- while : condition 충족 시, body 실행
- Do while : body 실행 후, condition이 충족되면 body 다시 실행
- for each : 리스트 목록의 항목을 한 번에 하나씩 body 반복

** Data Manipulation // variables
1. scalar variables
- 고정된 형식의 단일 값을 가진다
- chracter, booleans, numbers, date times

2. collections
- array와 list는 대부분 동일하지만, array는 고정된 크기를 갖는 반면 list는 요소를 추가/제거 하며 크기를 변동할 수 있다.
- arrays, lists, queues
- strings : 텍스트는 문자열이기 때문에, string의 확장된 형식으로서 strings를 사용한다.
- dictionaries : key 값과 value 값이 1:1로 상응하는 형식으로, orchestrator의 queue에서 데이터를 가져오는데 사용한다.

3. table
- 행과 컬럼으로 인덱싱된 데이터를 포함하는 2차원 구조
- dictionary의 array와 비슷하게 행 인덱스와 컬럼 이름으로 값에 엑세스 할 수 있다.

4. Read CSV properties
- FilePath : 불러올 CSV 파일의 경로
- Encoding : 한글 사용하는 경우 -> "euc-kr" 설정
- HasHeaders : 제일 첫 행을 헤더로 간주함
- DataTable : 불러온 CSV 파일을 DataTable 타입의 변수에 저장

5. Outpu data Table Properties
- DataTable을 String 형태로 변환
- DataTable : String으로 변환 할 DataTable 타입의 변수 지정
- Text : String 타입의 변수에 저장
-> Msg Box에 출력시, String 타입으로 출력 (+.toString)

6. datatable practice
- 로딩한 CSV 파일을 DataTable 타입의 변수에 저장
- name컬럼의 0번째 항목을 acess : sampleData.Rows(0)("name").ToString
- name컬럼의 모든 항목을 acess : row("name").ToString
- Age컬럼의 항목 중 40 이상이며, info컬럼의 항목 중 20K 이상인 항목 acess : sampleData.Select("Age>40 and info>'20K'")

- 컬럼 값을 forEachRow activity로 출력 : item("name").ToString
- 컬럼 값을 forEach activity로 출력 : item("name").ToString + " " + item("age").ToString + " " + item("info").ToString
-> 출력 방법은 동일하지만, 변수 타입이 DataTable인 경우에 ForEachRow를 쓰면 따로 properties의 조정 없이 사용할 수 있다.


7. recoding practice
- 처음과 끝에 로그 메세지 찍어주는게 좋음 -> error를 빨리 찾을 수 있음
- send hot key 보다는 click 액티비티를 사용하길 권장
- web을 열 때는 open browser를 사용
- click 없이 바로 type into text를 사용하는 것이 좋음
- simulateType 속성이 true이면 실행속도가 빨라짐


 

Level1_Ex03.xaml
0.02MB
Level1_Ex04.xaml
0.01MB
Level1_Ex05.xaml
0.01MB
Level1_Ex06.xaml
0.01MB
Level1_Ex07.xaml
0.02MB

+ Recent posts