# Smart Home Security System Guide

`action.devices.types.SECURITYSYSTEM` - Security systems can be armed and disarmed. They can be armed at multiple security levels (for example, home and away) and they can report information about certain sensors, such as a sensor that detects motion or an open window.

This type indicates that the device gets the Security System icon and some related
synonyms and aliases.

> [!NOTE]
> **Note:** You should use [secondary user verification](https://developers.home.google.com/cloud-to-cloud/enhancements/secondary-user-verification) for this trait with the `DOOR`, `GARAGE`, `GATE`, or `WINDOW` device type.

## Device capabilities

Refer to the corresponding trait documentation for
implementation details, such as attributes and states that your service should support, and how to
build EXECUTE and QUERY responses.

### Required traits

These traits and commands are required, if applicable to your
device. If your device does not support these traits, enter the error code of
`functionNotSupported` in a QUERY or EXECUTE response. See
[Errors and exceptions](https://developers.home.google.com/cloud-to-cloud/intents/errors-exceptions) for more info.

- [`action.devices.traits.ArmDisarm`](https://developers.home.google.com/cloud-to-cloud/traits/armdisarm)

### Recommended traits

These traits are recommended, if applicable to your device.
However, you are free to mix and match from all available traits to best match your existing
product functionality.

- [`action.devices.traits.StatusReport`](https://developers.home.google.com/cloud-to-cloud/traits/statusreport)

## Example device: Simple security system

This section contains example intent payloads representing a common "Security System"
based on the device type and traits above. If you add or remove traits in your implementation,
modify your responses accordingly to reflect those changes.

### Sample SYNC response

Request

```
{
  "requestId": "6894439706274654512",
  "inputs": [
    {
      "intent": "action.devices.SYNC"
    }
  ]
}
```
Response

```
{
  "requestId": "6894439706274654512",
  "payload": {
    "agentUserId": "user123",
    "devices": [
      {
        "id": "123",
        "type": "action.devices.types.SECURITYSYSTEM",
        "traits": [
          "action.devices.traits.StatusReport",
          "action.devices.traits.ArmDisarm"
        ],
        "name": {
          "name": "Simple security system"
        },
        "willReportState": true,
        "attributes": {
          "availableArmLevels": {
            "levels": [
              {
                "level_name": "home_key",
                "level_values": [
                  {
                    "level_synonym": [
                      "Home and Guarding",
                      "level 1",
                      "home",
                      "SL1"
                    ],
                    "lang": "en"
                  }
                ]
              },
              {
                "level_name": "away_key",
                "level_values": [
                  {
                    "level_synonym": [
                      "Away and Guarding",
                      "level 2",
                      "away",
                      "SL2"
                    ],
                    "lang": "en"
                  }
                ]
              }
            ],
            "ordered": true
          }
        },
        "deviceInfo": {
          "manufacturer": "smart-home-inc",
          "model": "hs1234",
          "hwVersion": "3.2",
          "swVersion": "11.4"
        }
      }
    ]
  }
}
```

### Sample QUERY response

Request

```
{
  "requestId": "6894439706274654514",
  "inputs": [
    {
      "intent": "action.devices.QUERY",
      "payload": {
        "devices": [
          {
            "id": "123"
          }
        ]
      }
    }
  ]
}
```
Response

```
{
  "requestId": "6894439706274654514",
  "payload": {
    "devices": {
      "123": {
        "status": "SUCCESS",
        "online": true,
        "isArmed": true,
        "currentArmLevel": "home_key",
        "currentStatusReport": [
          {
            "blocking": false,
            "deviceTarget": "123",
            "priority": 0,
            "statusCode": "lowBattery"
          }
        ]
      }
    }
  }
}
```

### Sample EXECUTE commands

#### ArmDisarm

For additional details on the command parameters,
see the [`action.devices.traits.ArmDisarm`](https://developers.home.google.com/cloud-to-cloud/traits/armdisarm#action.devices.commands.armdisarm) reference.

> [!NOTE]
> For commands which have a naturally longer process time, please use the `PENDING` status in the EXECUTE response and follow-up with the [ReportStateAndNotification API](https://developers.home.google.com/cloud-to-cloud/integration/notifications#send-notification) when the command has been completed.

Request

```
{
  "requestId": "6894439706274654516",
  "inputs": [
    {
      "intent": "action.devices.EXECUTE",
      "payload": {
        "commands": [
          {
            "devices": [
              {
                "id": "123"
              }
            ],
            "execution": [
              {
                "command": "action.devices.commands.ArmDisarm",
                "params": {
                  "arm": true,
                  "armLevel": "away_key"
                }
              }
            ]
          }
        ]
      }
    }
  ]
}
```
Response

```
{
  "requestId": "6894439706274654516",
  "payload": {
    "commands": [
      {
        "ids": [
          "123"
        ],
        "status": "PENDING",
        "states": {
          "online": true,
          "isArmed": true,
          "currentArmLevel": "away_key"
        }
      }
    ]
  }
}
```

## Device ERRORS

See the full list of [errors and exceptions](https://developers.home.google.com/cloud-to-cloud/intents/errors-exceptions).

## Report arming exceptions

When attempting to arm or disarm the system, you can provide additional
context via [exceptions codes](https://developers.home.google.com/cloud-to-cloud/intents/errors-exceptions#exceptions)
that you report through the [StatusReport](https://developers.home.google.com/cloud-to-cloud/traits/statusreport) trait.
Exceptions can be reported as blocking or non-blocking.

- **Non-blocking exceptions** reported with a "SUCCESS" status indicate that the exception did not prevent arming or disarming.
- **Blocking exceptions** reported with an "EXCEPTIONS" status indicate that arming or disarming was stopped because of these exceptions.

Exception codes that are commonly associated with security systems include:

- `doorOpen`: A door is open.
- `windowOpen`: A window is open.
- `isOpen`: A sensor detects something is open (but doesn't know if it's a door or window).

> [!NOTE]
> **Note:** If the security system hub is offline, it should not be reported within the `currentStatusReport` field, but instead in the regular `errorCode` field.

### Example: Non-blocking exception

This example shows a non-blocking exception where the security system is
armed even though a window is reported as open.

|---|---|
| **User** | Set the security system to high security. |
| **Google Assistant** | Ok, the front window is open. Arming security system to high security. |

> [!NOTE]
> **Note:** The text to speech "The front window is open" is generated based on the `currentStatusReport` field in the response.

Request

    {
        "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
        "inputs": [{
          "intent": "action.devices.EXECUTE",
          "payload": {
            "commands": [{
              "devices": [{
                "id": "123"
              }],
              "execution": [{
                "command": "action.devices.commands.ArmDisarm",
                "params": {
                  "arm": true,
                  "armLevel": "L2"
                }
              }]
            }]
          }
        }]
      }

Response

    {
        "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
        "payload": {
          "commands": [
            {
              "ids": [
                "123"
              ],
              "status": "SUCCESS",
              "states": {
                "online": true,
                "isArmed": true,
                "currentArmLevel": "L2",
                "currentStatusReport": [
                  {
                    "blocking": false,
                    "priority": 0,
                    "statusCode": "windowOpen",
                    "deviceTarget": "sensor_id1"
                  }
                ]
              }
            }
          ]
        }
      }

### Example: Blocking exception

|---|---|
| **User** | Set the security system to high security. |
| **Google Assistant** | There was an error controlling the security system. The front window is open. |

> [!NOTE]
> **Note:** The text to speech "The front window is open" is generated based on the `currentStatusReport` field in the response.

Request

    {
        "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
        "inputs": [{
          "intent": "action.devices.EXECUTE",
          "payload": {
            "commands": [{
              "devices": [{
                "id": "123"
              }],
              "execution": [{
                "command": "action.devices.commands.ArmDisarm",
                "params": {
                  "arm": true,
                  "armLevel": "L2"
                }
              }]
            }]
          }
        }]
      }

Response 2

    {
        "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
        "payload": {
          "commands": [
            {
              "ids": [
                "123"
              ],
              "status": "EXCEPTIONS",
              "states": {
                "online": true,
                "isArmed": false,
                "currentArmLevel": "L2",
                "currentStatusReport": [
                  {
                    "blocking": true,
                    "priority": 0,
                    "statusCode": "windowOpen",
                    "deviceTarget": "sensor_id1"
                  }
                ]
              }
            }
          ]
        }
      }

## Arming with two-factor authentication

If your arming flow requires users to input a PIN through a
[two-factor authentication](https://developers.home.google.com/cloud-to-cloud/enhancements/secondary-user-verification) dialog,
you **must acknowledge whether they would like to continue arming the system when there are active
exceptions** (for example, when a window or door is open).

This scenario may require *both* a PIN or passphrase entry, followed by an acknowledgment.

> [!NOTE]
> **Note:**The platform expects that you store this state information, as Google will not hold a user's PIN or passphrase through multiple dialog turns.

### Example: Acknowledgement challenge

This example shows a user attempting to arm the security system, but a
front door is detected as open. The user acknowledges that the security
system should be armed even though the front door is open.

|---|---|
| **User** | Arm the security system. |
| **Google Assistant** | The front door is open. Are you sure you want to arm the security system? |
| **User** | Yes. |
| **Google Assistant** | Ok, arming the security system. |

In the first turn, you should respond with an `ackNeeded` challenge.
Request 1

    {
        "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
        "inputs": [{
          "intent": "action.devices.EXECUTE",
          "payload": {
            "commands": [{
              "devices": [{
                "id": "123"
              }],
              "execution": [{
                "command": "action.devices.commands.ArmDisarm",
                "params": {
                  "arm": true
                }
              }]
            }]
          }
        }]
      }

Response 2

    {
        "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
        "payload": {
          "commands": [
            {
              "ids": [
                "123"
              ],
              "status": "ERROR",
              "errorCode": "challengeNeeded",
              "challengeNeeded": {
                "type": "ackNeeded"
              },
              "states": {
                "isArmed": true,
                "currentArmLevel": "L2",
                "currentStatusReport": [
                  {
                    "blocking": false,
                    "priority": 0,
                    "statusCode": "doorOpen",
                    "deviceTarget": "456"
                  }
                ]
              }
            }
          ]
        }
      }

The subsequent request from Google to you will contain the `ack` result.
Request 2

    {
        "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
        "inputs": [{
          "intent": "action.devices.EXECUTE",
          "payload": {
            "commands": [{
              "devices": [{
                "id": "123"
              }],
              "execution": [{
                "command": "action.devices.commands.ArmDisarm",
                "params": {
                  "arm": true
                },
                "challenge": {
                  "ack": true
                }
              }]
            }]
          }
        }]
      }

Response

    {
        "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
        "payload": {
          "commands": [
            {
              "ids": [
                "123"
              ],
              "status": "SUCCESS",
              "states": {
                "isArmed": true
              }
            }
          ]
        }
      }

### Example: PIN and acknowledgement challenge

This example shows a user attempting to arm the security system requiring PIN input.
The system detects that the front and back windows are open and asks the user to acknowledge
that arming should proceed.

|---|---|
| **User** | Arm to away. |
| **Google Assistant** | What's your PIN? |
| **User** | 1234. |
| **Google Assistant** | It looks like the front window and back window are open. Are you sure you want to continue arming the security system to away? |
| **User** | Yes. |
| **Google Assistant** | Okay, arming the security system to away |

In the first turn, you should respond with a standard `pinNeeded` challenge.
Request 1

```
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "inputs": [{
    "intent": "action.devices.EXECUTE",
    "payload": {
      "commands": [{
        "devices": [{
          "id": "123"
        }],
        "execution": [{
          "command": "action.devices.commands.ArmDisarm",
          "params": {
            "arm": true
          }
        }]
      }]
    }
  }]
}
```
Response

```
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "commands": [{
      "ids": ["456"],
      "status": "ERROR",
      "errorCode": "challengeNeeded",
      "challengeNeeded": {
        "type": "pinNeeded"
      }
    }]
  }
}
```

Google then follows up with a request containing the provided PIN. In order to support
the second turn, you should respond with an `ackNeeded` challenge with
additional information, including the target arm level, and the current status report with
blocking exceptions.
Request 2

```
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "inputs": [{
    "intent": "action.devices.EXECUTE",
    "payload": {
      "commands": [{
        "devices": [...],
        "execution": [{
          "command": "action.devices.commands.ArmDisarm",
          "params": {
            "arm": true,
            "armLevel": "away"
          },
          "challenge": {
            "pin": "1234"
          }
        }]
      }]
    }
  }]
}
```
Response

```
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "commands": [{
      "ids": ["456"],
      "status": "ERROR",
      "states": {
        "targetArmLevel": "away",
        "currentStatusReport": [{
            "blocking": true,
            "priority": 1,
            "deviceTarget": "front_window_id",
            "statusCode": "deviceOpen"
          },
          {
            "blocking": true,
            "priority": 1,
            "deviceTarget": "back_window_id",
            "statusCode": "deviceOpen"
          }
        ]
      },
      "errorCode": "challengeNeeded",
      "challengeNeeded": {
        "type": "ackNeeded"
      }
    }]
  }
}
```

The subsequent request from Google to you will contain only the `ack` result,
and not the PIN provided in the first turn.
Request 3

```
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "inputs": [{
    "intent": "action.devices.EXECUTE",
    "payload": {
      "commands": [{
        "devices": [...],
        "execution": [{
          "command": "action.devices.commands.ArmDisarm",
          "params": {
            "arm": true,
            "armLevel": "away"
          },
          "challenge": {
            "ack": true
          }
        }]
      }]
    }
  }]
}
```
Response

```
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "commands": [
      {
        "ids": [
          "123"
        ],
        "status": "SUCCESS",
        "states": {
          "isArmed": true
        }
      }
    ]
  }
}
```