루틴(Rules)

루틴(Rules)은 SmartThings 플랫폼에 연결하는 기기와 서비스를 자동화할 수 있는 다목적 도구입니다. 규칙은 특정 이벤트가 일어날 때 기기를 자동으로 움직이고, 조명을 특정 간격으로 바꾸는 것과 같은 반복적인 일을 자동화하고, 유저에게 "설정하고 잊어버리기" 기능을 제공하는 쓰임새가 있습니다.

우리는 빠른 속도가 좋은 유저 경험을 보장하는 데 중요하다고 믿습니다. 그렇기 때문에 가능한 경우 루틴(Rules)이 허브에서 로컬로 돌아갑니다. 루틴(Rules)을 로컬로 돌아가게 하려면 루틴(Rules)과 관련된 모든 기기의 기능과 서비스가 로컬 네트워크에서의 로컬 실행을 지원해야 합니다. 로컬 실행을 지원하지 않는 기능 또는 서비스와 관련된 루틴(Rules)은 SmartThings Cloud에서 돌아갑니다.

## 루틴의 짜임새

루틴(Rules)은 JSON 형식으로 정의되며 이름, 설치 원본 및 액션의 리스트를 포함합니다. 하나의 루틴(Rules)은 여러 액션을 하는 데에 쓰일 수 있습니다. 루틴(Rules)이 켜질 때의 이러한 액션은 큰 나무의 생김새(트리 구조)로 나타납니다

액션은 Rules API의 핵심 구성 요소이며 루틴(Rules)이 움직이는 방식을 정의합니다. SmartThings에서 쓰이는 짜임새와 구문을 더 잘 이해하기 위해 아래의 그림에서 루틴(Rules)의 예를 살펴보겠습니다.

이 루틴(Rules)은 기기의 접촉 센서(구문에서 `left`)를 구문 `right`에 정의된 값과 비교하는 일을 합니다.

위의 루틴(Rules)을 알아보면 다음과 같습니다.

1. 액션 - 액션은 루틴(Rules)이 완료하는 작업을 정의합니다. 액션은 액션 배열에 포함되어 있습니다. 하나의 루틴(Rules)에 여러 액션을 지정할 수 있습니다. 이 경우 액션은 `if` 문입니다.
2. 조건(Condition) - 작업에 대한 트리거로 쓰이는 실행자(evaluation)입니다. 조건은 루틴(Rules)이 실행 중에 평가되며 작업에 포함됩니다. 이 때 조건(Condition)은 `equals` 문입니다.
3. 피연산자(Operands) - 루틴(Rules)과 관련된 기기나 장소입니다. 이 경우 접촉 센서와 스위치는 루틴(Rules)에 포함됩니다.
4. 결과 - 이 경우 액션입니다. 만약 지금의 조건 `equals` 이 루틴에서 지정한 조건과 같음을 알게 되면, 루틴(Rules)이 명령을 따릅니다. 조건이 충족되지 않으면 `else` 블록의 모든 코드가 돌아갑니다.

액션
--

액션은 하나 이상의 조건(Conditions)으로 구성됩니다. 쓰는 액션의 타입에 따라 쓸 수 있는 조건(Conditions)이 정해집니다. GitHub 페이지를 들어가서 자동화 예제를 보고 각 조건(Conditions)의 타입이 쓰이는 포맷을 알아보세요.

다음은 일반적으로 쓰는 몇 가지 액션입니다.

* `if` - 조건(Condition)이 true로 여겨지면 `then` 블록에 있는 액션을 켭니다. 그렇지 않으면 `else` 블록이 켜집니다.
* `sleep` - 조건문의 나머지 코드를 켜기 전에 기다릴 시간의 간격을 고릅니다.
* `command` - 하나 또는 여러 기기를 움직이는 데에 쓰이는 간단한 조건(Condition)입니다.
* `every` - 지정된 조건(Condition)이 true로 여겨지면 지정된 액션을 켭니다.

## 조건(Condition)

조건은 액션 안에서 겹치며 하나 이상의 피연산자로 이뤄집니다. 쓰는 조건의 타입에 따라 필요한 피연산자의 유형과 수가 결정됩니다. 예를 들어 `lessThanOrEquals` 조건에는 `left`과 `right`의 두 피연산자가 필요합니다. GitHub 페이지를 들어가서 자동화 예제를 보고 각 조건의 타입이 쓰이는 포맷을 알아보세요.

다음은 일반적으로 쓰는 몇가지 조건입니다.

* `and` + `or`
* `not`
* `equals`
* `greaterThan` + `lessThan`
* `greaterThanOrEquals` + `lessThanOrEquals`
* `between`
* `changes`

### `and` + `or`

```
"if": {
   "and": [
       {
           "equals": {
               "left": {
                   "location": {
                       "attribute": "Mode"
                   }
               },
               "right": {
                   "string": "<insert-the-mode-id-here>"
               }
           }
       },
       {
           "between": {...}
       }
   ],
   "then":[...]
}
```

### `not`

이 조건은 하고있는 일을 반전시킵니다. 아래 예에서 스위치의 현재 상태가 on과 다른 경우 조건이 true인 것으로 알게 됩니다.

```
"if": {
   "not": {
       "equals": {
           "left": {
               "device": {
                   "devices": [
                       "<insert-device-id-here>"
                   ],
                   "component": "main",
                   "capability": "switch",
                   "attribute": "switch"
               }
           },
           "right": {
               "string": "on"
           }
       }
   },
   "then":[...]
}
```

### `equals`

이 조건은 같은 값에 대해 왼쪽과 오른쪽을 비교합니다.

이 예에서 왼쪽에 주어진 스위치 기기의 피연산자는 오른쪽에 주어진 문자열에 대해 알아보게 됩니다. 왼쪽 및 오른쪽 값이 동일하면 조건이 true인 것으로 알게 됩니다.

```
"equals": {
    "left": {
        "device": {
            "devices": ["<insert-your-device-ID-here>"],
            "component": "main",
            "capability": "switch",
            "attribute": "switch"
        }
    },
    "right": {
        "string": "on"
    }
}
```

### `greaterThan` + `lessThan`

이 조건은 왼쪽에 지정된 값이 오른쪽에 지정된 속성(attribute)의 현재 값보다 크거나 작은지 찾아봅니다. 이 예에서 스위치의 현재 레벨이 지정된 정수보다 크면 조건은 true입니다.

이 조건은 지정된 값보다 크거나 작은 각 이벤트에 대해 true인 것으로 알게 됩니다. 예를 들어 온도가 50도를 넘을 때 온도 조절기를 제어하기 위해 `greaterThan`을 쓰는 경우 루틴(Rules)은 true인 것으로 알게 되어 50도를 넘는 각 간격마다 돌아갑니다. 값이 설정 포인트 위(또는 아래)로 바뀔 때 조건이 한 번만 실행되도록 하려면, `greaterThan` 조건을 `changes` 조건으로 감싸세요.

```
"greaterThan": {
    "left": {
        "integer": 50
    },
    "right": {
        "device": {
            "devices": ["your-device-id-here"],
            "component": "main",
            "capability": "switchLevel",
            "attribute": "level"
        }
    }
}
```

### `lessThanOrEquals` + `greaterThanOrEquals`

이러한 조건은 `lessThan` 및 `greaterThan`의 비튼 생김새이며, 같은 지에 대해 2번째의 검사를 더합니다. 아래 예에서 왼쪽에 지정된 정수는 스위치의 현재 레벨에 대해 찾아봅니다. 스위치의 현재 레벨이 지정된 정수보다 작거나 같으면 조건이 참입니다.

이 조건은 지정된 값보다 크거나 작은 각 이벤트에 대해 true인 것으로 알게 됩니다. 예를 들어, 온도가 50도보다 크거나 같을 때 온도 조절기를 제어하기 위해 `greaterThanOrEquals`를 쓸 때, 루틴(Rules)은 true인 것으로 알고, 50도를 넘는 각 간격마다 돌아갑니다(51도에서 한 번 켜기, 52도에서 다시 켜기 등). 값이 설정 포인트 위(또는 아래)로 바뀔 때 조건이 한 번만 실행되도록 하려면 `greaterThan` 조건을 `changes` 조건으로 감싸세요.

```
"lessThanOrEquals": {
    "left": {
        "integer": 50
    },
    "right": {
        "device": {
            "devices": ["your-device-id-here"],
            "component": "main",
            "capability": "switchLevel",
            "attribute": "level"
        }
    }
}
```

### `between`

주어진 속성(attribute)이 제공된 두 값 사이에 있는지 확인하세요.

이 예에서 속성(attribute)레벨이 시작과 끝에 있는 정수 사이에 있으면 조건은 참입니다.

```
"between": {
    "value": {
        "device": {
            "devices": ["your-device-id-here"],
            "component": "main",
            "capability": "switchLevel",
            "attribute": "level"
        }
    },
    "start": {
        "integer": 50
    },
    "end": {
        "integer": 75
    }
}
```

### `changes`

`changes` 는 조건의 안에 있는 일의 상태를 알아보는 조건으로, 조건 안의 일의 상태가 false에서 true로 바뀔 때 조건은 참입니다

### `changes` 를 `lessThan` 와 함께 쓰기

아래 예에서, 밝기 조절 스위치(조광기, 디머 스위치)의 스위치 레벨이 주어진 값 50보다 아래로 바뀌면 조건을 true인 것으로 알게 됩니다. 조광기가 처음 50보다 위로 바뀌고 나서부터 50보다 아래로 바뀔 때까지는 조건을 true인 것으로 알지 않습니다.

```
"changes": {
    "lessThan": {
        "left": {
            "device": {
                "devices": [
                    "{{your-device-id-here}}"
                ],
                "component": "main",
                "capability": "switchLevel",
                "attribute": "level",
            }
        },
        "right": {
            "integer": 50
        }
    }
}
```

## 피연산자(Operands)

피연산자는 조건 안에서 쓰입니다. 피연산자는 루틴(Rules)에 쓰기로 고른 조건에 지정된 값(종종 정수 또는 문자열)에 대해 알아봅니다.

간단히 말해서 피연산자는 일반적으로 루틴(Rules)에서 알아보려는 기기나 장소입니다.

일반적으로 쓰이는 피연산자는 다음과 같습니다.

* `device` - 기기의 속성(attribute)을 알아봅니다.
* `location` - 장소 모드의 상태를 알아봅니다.
* `array` - 여러 피연산자를 포함하는 배열입니다.
* `specific` - 일이 true인 것으로 알게 된 때 쓰이는 특정 인스턴스입니다.
* `trigger` - SmartThings 앱에서 "선행 조건"이라고 합니다. 루틴(Rules)에 여러 개의 조건이 있을 때, 조건 하나가 루틴(Rules)을 트리거하고 실행하는 것을 막기 위해 선행 조건 또는 트리거를 쓸 수 있습니다.

### `specific`

이 피연산자는 every 액션과 함께 쓰이며 일이 true인 것으로 알게 되는 특정 인스턴스를 제공합니다.

아래 예에서 조건은 매일 오전 11:55에 true인 것으로 알게 되고 지정된 장소의 mode를 바꿉니다.

```
"every": {
   "specific": {
         "reference": "Noon",
         "offset": {
             "value": {
                 "integer": -65
             },
             "unit": "Minute"
         }
   },
  "actions": [
       {
           "location": {
             "mode": "your-location-mode-id-here"
           }
       }
   ]
}
```

### `trigger`

`trigger` 나 선행조건을 써서, 루틴(Rules) 실행을 켜야 하는 조건과 켜지 않아야 하는 조건을 제대로 알 수 있도록 합니다.

루틴(Rules) 에 여러 조건을 넣으면 각 조건이 트리거 역할을 할 수도 있습니다. 이는 트리거로 지정된 조건이 `true`로 인 것으로 알게 되는 즉시 루틴(Rules)이 실행됨을 의미합니다(예: `if` 액션에서 `then` 블록이 실행됨).

* 조건이 루틴(Rules)을 켜는 것을 막으려면 `"trigger":"Never"`를 쓰세요.
* 조건이 루틴(Rules)을 켜도록 하려면 `"trigger":"Always"`를 쓰세요.

아래 예의 루틴(Rules)에서:

* `if` 액션이 `equals` 랑 같이 쓰이는 조건에서는 `button-device-id`가 눌러지면(`"trigger":"Always"`를 쓸 때, 이 조건이 이 루틴(Rules)의 트리거로 쓰이게 됨을 나타냅니다) 루틴(Rules)이 `switch1-device-id`가 on이 되었는지를 알아봅니다.
* `switch1`이 켜져 있으면 루틴(Rules)에 따라 `switch1-device-id`를 on으로 만듭니다. 이 `then` 문에서 `"trigger":"Never"`를 쓰면 `switch1` 이 켜져 있을 때마다 이 조건이 루틴(Rules)을 켜려고 하지 않습니다. 이 조건은 대신 나머지 루틴(Rules)의 논리에 대해 알아보는 쓰임새로 쓰여 루틴(Rules)의 다음 일을 결정합니다.
* 다른 모든 경우(`else`)의 경우 루틴(Rules)은 `switch2` 를 끕니다.

```
{
    "name": "Sample for precondition",
    "actions": [
        {
            "if":{
                "equals": {
                    "left":{
                        "string": "pushed"
                    },
                    "right":{
                        "device":{
                            "devices":["button-device-id"],
                            "component": "main",
                            "capability":"button",
                            "attribute":"button",
                            "trigger":"Always"
                        }
                    }
                },
                "then":[
                    {
                        "if": {
                            "equals": {
                                "left": {
                                    "device": {
                                        "devices": [
                                            "switch1-device-id"
                                        ],
                                        "component": "main",
                                        "capability": "switch",
                                        "attribute": "switch",
                                        "trigger":"Never"
                                    }
                                },
                                "right": {
                                    "string": "on"
                                }
                            },"then":[
                            {
                                "command": {
                                    "devices": [
                                        "switch2-device-id"
                                    ],
                                    "commands": [
                                        {
                                            "component": "main",
                                            "capability": "switch",
                                            "command": "on",
                                            "arguments": []
                                        }
                                    ]
                                }
                            }],"else":[{
                                "command": {
                                    "devices": [
                                        "switch2-device-id"
                                    ],
                                    "commands": [
                                        {
                                            "component": "main",
                                            "capability": "switch",
                                            "command": "off",
                                            "arguments": []
                                        }
                                    ]
                                }
                            }]
                        }
                    }
                ]
            }
        }
    ]
}
```