Smart Home OpenClose Trait Schema

action.devices.traits.OpenClose - This trait belongs to devices that support opening and closing, and in some cases opening and closing partially or potentially in more than one direction. For example, some blinds may open either to the left or to the right. In some cases, opening certain devices may be a security sensitive action which can require two-factor authentication authentication. See Two-factor authentication.

Device ATTRIBUTES

Attribute Definition
openDirection Array of strings. Optional. Required if the device supports opening and closing in more than one direction. Comma-separated list of directions in which this device can be opened. Valid options include: UP, DOWN, LEFT, RIGHT, IN, and OUT. For example, top-down bottom-up blinds may open either up or down.
queryOnlyOpenClose Boolean. Optional. Indicates if the device can only be queried for state information and cannot be controlled. Sensors that can only report open state should set this field to true.

Sample SYNC Request and Response

Request
{
    "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
    "inputs": [{
      "intent": "action.devices.SYNC"
    }]
}
Node.js
'use strict';

const {smarthome} = require('actions-on-google');
const functions = require('firebase-functions');

const app = smarthome();

app.onSync((body, headers) => {
  return {
    requestId: body.requestId,
    payload: {
      agentUserId: '1836.15267389',
      devices: [{
        id: '123',
        type: 'action.devices.types.BLINDS',
        traits: [
          'action.devices.traits.OpenClose'
        ],
        name: {
          defaultNames: [
            'Blinds'
          ],
          name: 'Kitchen window',
          nicknames: [
            'Sink window'
          ]
        },
        willReportState: true,
        attributes: {
          openDirection: ['UP', 'DOWN']
        },
        deviceInfo: {
          manufacturer: 'ACME',
          model: '492134',
          hwVersion: '3.2',
          swVersion: '11.4'
        },
        customData: {
          fooValue: 74,
          barValue: true,
          bazValue: 'lambtwirl'
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
Java
@NotNull
@Override
public SyncResponse onSync(@NotNull SyncRequest syncRequest, @Nullable Map<?, ?> headers) {
  Payload payload = new Payload();
  payload.setAgentUserId("1836.15267389");
  payload.setDevices(new Device[] {
      new Device.Builder()
          .setId("123")
          .setType("action.devices.types.BLINDS")
          .addTrait("action.devices.traits.OpenClose")
          .setName(
              Collections.singletonList("Blinds"),
              "Kitchen window",
              Collections.singletonList("Sink window")
          )
          .setWillReportState(true)
          .setAttributes(new JSONObject()
              .put("openDirection", new String[] {"UP", "DOWN"})
          )
          .setDeviceInfo("ACME", "492134", "3.2", "11.4")
          .setCustomData(new JSONObject()
              .put("fooValue", 74)
              .put("barValue", true)
              .put("bazValue", "lambtwirl")
              .toString()
          )
          .build()
  });
  return new SyncResponse(syncRequest.getRequestId(), payload);
}
JSON
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "agentUserId": "1836.15267389",
    "devices": [
      {
        "id": "123",
        "type": "action.devices.types.BLINDS",
        "traits": [
          "action.devices.traits.OpenClose"
        ],
        "name": {
          "defaultNames": [
            "Blinds"
          ],
          "name": "Kitchen window",
          "nicknames": [
            "Sink window"
          ]
        },
        "willReportState": true,
        "attributes": {
          "openDirection": [
            "UP",
            "DOWN"
          ]
        },
        "deviceInfo": {
          "manufacturer": "ACME",
          "model": "492134",
          "hwVersion": "3.2",
          "swVersion": "11.4"
        },
        "customData": {
          "fooValue": 74,
          "barValue": true,
          "bazValue": "lambtwirl"
        }
      }
    ]
  }
}
Validator

Device STATES

This trait uses different device STATES depending on if the device opens in single or multiple directions.

Multiple opening directions

State Definition
openState Required if the device opens in more than one direction. Contains the following:
  • openPercent Float. [0, 100]. Required. Indicates the percentage that a device is opened where 0 is closed and 100 is fully open.
  • openDirection String. Required. Direction in which the device is opened.

Example:

"openState": [{
  "openPercent": 30,
  "openDirection": "DOWN" },
{
  "openPercent": 50
  "openDirection": "UP" }
]

Figure 1 shows an example of a top-down bottom-up blind where the UP direction raises the bottom portion of the blinds by 50 percent and the DOWN direction lowers the top portion of the blinds by 30 percent.

Figure 1 - Top-down bottom-up blind

Sample QUERY Request and Response

User Are my blinds open?
Google Assistant The kitchen blinds are open.
Request
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "inputs": [{
    "intent": 'action.devices.QUERY',
    "payload": {
      "devices": [{
        "id": "123",
        "customData": {
          "fooValue": 74,
          "barValue": true,
          "bazValue": "foo"
        }
      }]
    }
  }]
}
Node.js
'use strict';

const {smarthome} = require('actions-on-google');
const functions = require('firebase-functions');

const app = smarthome();

app.onQuery((body, headers) => {
  return {
    requestId: body.requestId,
    payload: {
      devices: {
        123: {
          on: true,
          online: true,
          openState: [{
            openPercent: 40.0,
            openDirection: 'DOWN'
          }]
        }
      }
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
Java
@NotNull
@Override
public QueryResponse onQuery(@NotNull QueryRequest queryRequest, @Nullable Map<?, ?> map) {
  QueryResponse.Payload payload = new QueryResponse.Payload();
payload.setDevices(new HashMap<String, Object>() {{    put("123", new HashMap<String, Object>() {{        put("on", true);
        put("online", true);
        put("openState", new HashMap[] {
            new HashMap<String, Object>() {{                put("openPercent", 40);
                put("openDirection", "DOWN");
            }}        });
    }});
    put("status", "SUCCESS");
}});
  return new QueryResponse(queryRequest.getRequestId(), payload);
}
JSON
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "devices": {
      "123": {
        "on": true,
        "online": true,
        "openState": [
          {
            "openPercent": 40,
            "openDirection": "DOWN"
          }
        ]
      }
    }
  }
}

Single opening direction

State Definition
openPercent Float. [0, 100]. Required. Indicates the percentage that a device is opened where 0 is closed and 100 is fully open.
openDirection String. Optional. Direction in which the device is opened.

Sample QUERY Request and Response

User Are my blinds open?
Google Assistant The kitchen blinds are open.
Request
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "inputs": [{
    "intent": 'action.devices.QUERY',
    "payload": {
      "devices": [{
        "id": "123",
        "customData": {
          "fooValue": 74,
          "barValue": true,
          "bazValue": "foo"
        }
      }]
    }
  }]
}
Node.js
'use strict';

const {smarthome} = require('actions-on-google');
const functions = require('firebase-functions');

const app = smarthome();

app.onQuery((body, headers) => {
  return {
    requestId: body.requestId,
    payload: {
      devices: {
        123: {
          on: true,
          online: true,
          openPercent: 100.0
        }
      }
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
Java
@NotNull
@Override
public QueryResponse onQuery(@NotNull QueryRequest queryRequest, @Nullable Map<?, ?> map) {
  QueryResponse.Payload payload = new QueryResponse.Payload();
payload.setDevices(new HashMap<String, Object>() {{    put("123", new HashMap<String, Object>() {{        put("on", true);
        put("online", true);
        put("openState", new HashMap[] {
            new HashMap<String, Object>() {{                put("openPercent", 40);
                put("openDirection", "DOWN");
            }}        });
    }});
    put("status", "SUCCESS");
}});
  return new QueryResponse(queryRequest.getRequestId(), payload);
}
JSON
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "devices": {
      "123": {
        "on": true,
        "online": true,
        "openPercent": 100
      }
    }
  }
}

Device COMMANDS

Command Parameters/Definition
action.devices.commands.OpenClose

openPercent Float. [0, 100]. Required. Indicates the absolute percentage that a device should open where 0 is closed and 100 is fully open. If no value is specified by the user (for example, Hey Google, open the blinds.), the value defaults to 100.

openDirection String. Optional. Direction in which to open. Valid values from list of supported directions. For example, for top-down bottom-up blinds, specify UP to raise the bottom only.

Sample EXECUTE Request and Response

User Open the garage door.
Google Assistant Opening the garage door.
Request
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "inputs": [{
    "intent": "action.devices.EXECUTE",
    "payload": {
      "commands": [{
        "devices": [{
          "id": "123",
          "customData": {
            "fooValue": 74,
            "barValue": true,
            "bazValue": "lambtwirl"
          }
        }],
        "execution": [{
          "command": "action.devices.commands.OpenClose",
          "params": {
            "openPercent": 100
          }
        }]
      }]
    }
  }]
}
Node.js
'use strict';

const {smarthome} = require('actions-on-google');
const functions = require('firebase-functions');

const app = smarthome();

app.onExecute((body, headers) => {
  return {
    requestId: body.requestId,
    payload: {
      commands: [{
        ids: ['123'],
        status: 'SUCCESS',
        states: {
          openPercent: 100.0,
          online: true
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
Java
@NotNull
@Override
public ExecuteResponse onExecute(@NotNull ExecuteRequest executeRequest, @Nullable Map<?, ?> map) {
  ExecuteResponse.Payload payload = new ExecuteResponse.Payload();
payload.setCommands(new Commands[] {
    new Commands(
        new String[] {"123"},
        "SUCCESS",
        new HashMap<String, Object>() {{            put("openPercent", 100);
            put("online", true);
        }},
        null
    )
});
  return new ExecuteResponse(executeRequest.getRequestId(), payload);
}
JSON
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "commands": [
      {
        "ids": [
          "123"
        ],
        "status": "SUCCESS",
        "states": {
          "openPercent": 100,
          "online": true
        }
      }
    ]
  }
}
User Open blinds 50 percent down.
Google Assistant Opening the blinds downward to 50 percent.
Request
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "inputs": [{
    "intent": "action.devices.EXECUTE",
    "payload": {
      "commands": [{
        "devices": [{
          "id": "456",
          "customData": {
            "fooValue": 74,
            "barValue": true,
            "bazValue": "lambtwirl"
          }
        }],
        "execution": [{
          "command": "action.devices.commands.OpenClose",
          "params": {
            "openPercent": 50,
            "openDirection": "DOWN"
          }
        }]
      }]
    }
  }]
}
Node.js
'use strict';

const {smarthome} = require('actions-on-google');
const functions = require('firebase-functions');

const app = smarthome();

app.onExecute((body, headers) => {
  return {
    requestId: body.requestId,
    payload: {
      commands: [{
        ids: ['123'],
        status: 'SUCCESS',
        states: {
          openState: [{
            openPercent: 50.0,
            openDirection: 'DOWN'
          }, {
            // Returns the position of the other blind section
            openPercent: 30.0,
            openDirection: 'UP'
          }],
          online: true
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
Java
@NotNull
@Override
public ExecuteResponse onExecute(@NotNull ExecuteRequest executeRequest, @Nullable Map<?, ?> map) {
  ExecuteResponse.Payload payload = new ExecuteResponse.Payload();
payload.setCommands(new Commands[] {
    new Commands(
        new String[] {"123"},
        "SUCCESS",
        new HashMap<String, Object>() {{            put("openState", new HashMap[] {
                new HashMap<String, Object>() {{                  put("openPercent", 50);
                  put("openDirection", "DOWN");
                }},
                new HashMap<String, Object>() {{                  put("openPercent", 30);
                  put("openDirection", "UP");
                }}            });
            put("online", true);
        }},
        null
    )
});
  return new ExecuteResponse(executeRequest.getRequestId(), payload);
}
JSON
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "commands": [
      {
        "ids": [
          "123"
        ],
        "status": "SUCCESS",
        "states": {
          "openState": [
            {
              "openPercent": 50,
              "openDirection": "DOWN"
            },
            {
              "openPercent": 30,
              "openDirection": "UP"
            }
          ],
          "online": true
        }
      }
    ]
  }
}
Note: In this example, both blind section positions are reported back.

Device ERRORS

  • lockedState Indicates that the device can't be opened since it is currently in a locked state.
  • deviceJammingDetected Indicates that the device is jammed.

See the full list of errors and exceptions.