Smart Home Dispense Trait Schema

action.devices.traits.Dispense - This trait belongs to devices that support dispensing a specified amount of one or more physical items. For example, a dog treat dispenser may dispense a number of treats, a faucet may dispense cups of water, and a pet feeder may dispense both water and pet food.

This trait also supports dispensing a preset, for example as a "cat food bowl" for a pet feeder or a "glass" for a faucet.

Device ATTRIBUTES

Attribute Definition
supportedDispenseItems Required array of objects. Contains information on all the items that the device can dispense, including the following details about each item:
  • item_name: Required string. The name or key for the item (for example, “water”, “dog treats”). This field is only used as the key for the synonyms and must also be included in the synonyms list if it is a valid name for the item.
  • item_name_synonyms: Required array of objects. Each object contains two pairs:
    • lang: String representing the language code (ISO 639-1).
    • synonyms: Array of strings of the synonyms for the item in that language. These synonyms must include all singular, plural, and gendered forms of the item. The first string in this list must be the plural form of the item in that language.
  • supported_units: Required array of strings. Indicates what set of units the device supports for that item. For example, water from a faucet would support units for liquids but not for length, whereas dog treats from a pet treat dispenser may only support NO_UNITS. See below for a list of all supported units.
  • default_portion: Required object. Indicates what is a typical amount of the item that may be dispensed (for example, the amount of water may be 2 cups). Each object contains two pairs:
    • amount: Float.
    • unit: String.

Example of the supportedDispenseItems format:

{
 "supportedDispenseItems": [{
  "item_name": "water",
  "item_name_synonyms": [{
    "lang": "en",
    "synonyms": [
     "water"
    ]
   },
   {
    "lang": "es",
    "synonyms": [
     "agua"
    ]
   },
   {
    "lang": "fr",
    "synonyms": [
     "eau"
    ]
   }
  ],
  "supported_units": [
   "TEASPOONS",
   "TABLESPOONS",
   "FLUID_OUNCES",
   "CUPS",
   "PINTS",
   "QUARTS",
   "GALLONS",
   "MILLILITERS",
   "LITERS",
   "DECILITERS"
  ],
  "default_portion": {
   "amount": 2.0,
   "unit": "CUPS"
  }
 }]
}
Attribute Definition
supportedDispensePresets Required array of objects. Contains the information on the various presets the device supports with the following details about each preset:
  • preset_name: Required string. The name or key for the item (for example, "water", "dog treats"). This field is only used as the key for the synonyms and must also be included in the synonyms list if it is a valid name for the item.
  • preset_name_synonyms: Array of objects. Each object contains two pairs:
    • lang: String representing the language code (ISO 639-1).
    • synonyms: Array of strings of the synonyms for the preset in that language. These synonyms must include all singular, plural, and gendered forms of the preset.

Example of the supportedDispensePresets format:

{
  "supportedDispensePresets": [{
    "preset_name": "cat water bowl",
    "preset_name_synonyms": [{
        "lang": "en",
        "synonyms": [
          "cat water bowl",
          "cat water dish"
        ]
      },
      {
        "lang": "es",
          "synonyms": [
            "plato de agua para gato",
            "bebedero para gato"
        ]
      },
      {
        "lang": "fr",
        "synonyms": [
          "bol d'eau de chat",
          "bac à eau pour chat",
          "tasse d'eau de chat"
        ]
      }
    ]
  }]
}

Supported units

The supported_units field can take any combination of the following units:

  • CENTIMETERS
  • CUPS
  • DECILITERS
  • FLUID_OUNCES
  • GALLONS
  • GRAMS
  • KILOGRAMS
  • LITERS
  • MILLIGRAMS
  • MILLILITERS
  • MILLIMETERS
  • NO_UNITS: When the item is countable so units are not needed (for example, dog treats).
  • OUNCES
  • PINCH
  • PINTS
  • PORTION: Generic unit of measurement to represent a “portion” of the item (device-specific).
  • POUNDS
  • QUARTS
  • TABLESPOONS
  • TEASPOONS

Sample SYNC Request and Response

This is an example using the device type and traits above. It is intended to give an idea of how to build a SYNC response. If you add or remove traits, this will need to be modified to reflect those changes.

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.FAUCET',
        traits: [
          'action.devices.traits.Dispense'
        ],
        name: {
          defaultNames: [
            'Faucet'
          ],
          name: 'Sink Faucet',
          nicknames: [
            'Faucet'
          ]
        },
        willReportState: true,
        attributes: {
          supportedDispenseItems: [{
            item_name: 'water',
            item_name_synonyms: [{
              lang: 'en',
              synonyms: ['water']
            }, {
              lang: 'es',
              synonyms: ['agua']
            }, {
              lang: 'fr',
              synonyms: ['eau']
            }],
            supported_units: [
              'TEASPOONS',
              'TABLESPOONS',
              'FLUID_OUNCES',
              'CUPS',
              'PINTS',
              'QUARTS',
              'GALLONS',
              'MILLILITERS',
              'LITERS',
              'DECILITERS'
            ],
            default_portion: {
              amount: 2.0,
              unit: 'CUPS'
            }
          }],
          supportedDispensePresets: [{
            preset_name: 'cat water bowl',
            preset_name_synonyms: [{
              lang: 'en',
              synonyms: [
                'cat water bowl',
                'cat water dish',
                'cat water cup'
              ]
            },{
              lang: 'es',
              synonyms: [
                'plato de agua para gato',
                'bebedero para gato'
              ]
            }, {
              lang: 'fr',
              synonyms: [
                `bol d'eau de chat`,
                'bac à eau pour chat',
                `tasse d'eau de chat`
              ]
            }]
          }]
        },
        customData: {
          fooValue: 42,
          barValue: true,
          catValue: "Fuzzy"
        }
      }]
    }
  };
});

// ...

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 SyncResponse.Payload.Device[] {
    new SyncResponse.Payload.Device.Builder()
        .setId("123")
        .setType("action.devices.types.FAUCET")
        .addTrait("action.devices.traits.Dispense")
        .setName(
            Collections.singletonList("Faucet"),
            "Sink Faucet",
            Collections.singletonList("Faucet")
        )
        .setWillReportState(true)
        .setAttributes(new JSONObject()
            .put("supportedDispenseItems", new JSONObject[]{
                new JSONObject()
                    .put("item_name", "water")
                    .put("item_name_synonyms", new JSONObject[] {
                        new JSONObject()
                            .put("lang", "en")
                            .put("synonyms", new String[] {"water"}),
                        new JSONObject()
                            .put("lang", "es")
                            .put("synonyms", new String[] {"agua"}),
                        new JSONObject()
                            .put("lang", "fr")
                            .put("synonyms", new String[] {"eau"})
                    })
                    .put("supported_units", new String[] {
                        "TEASPOONS",
                        "TABLESPOONS",
                        "FLUID_OUNCES",
                        "CUPS",
                        "PINTS",
                        "QUARTS",
                        "GALLONS",
                        "MILLILITERS",
                        "LITERS",
                        "DECILITERS"
                    }),
                    .put("default_portion", new JSONObject()
                        .put("amount", 2.0)
                        .put("unit", "CUPS")
                    )
            })
            .put("supportedDispensePresets", new JSONObject[] {
                new JSONObject()
                    .put("preset_name", "cat water bowl")
                    .put("preset_name_synonyms", new JSONObject[] {
                        new JSONObject()
                            .put("lang", "en")
                            .put("synonyms", new String[] {
                                "cat water bowl",
                                "cat water dish",
                                "cat water cup"
                            }),
                        new JSONObject()
                            .put("lang", "es")
                            .put("synonyms", new String[] {
                                "plato de agua para gato",
                                "bebedero para gato"
                            }),
                        new JSONObject()
                            .put("lang", "fr")
                            .put("synonyms", new String[] {
                                "bol d'eau de chat",
                                "bac à eau pour chat",
                                "tasse d'eau de chat"
                            })
                    })
            })
        )
        .setDeviceInfo("Sirius Cybernetics Corporation", "492134", "3.2", "11.4")
        .setCustomData(new JSONObject()
            .put("fooValue", 42)
            .put("barValue", true)
            .put("catValue", "Fuzzy")
            .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.FAUCET",
        "traits": [
          "action.devices.traits.Dispense"
        ],
        "name": {
          "defaultNames": [
            "Faucet"
          ],
          "name": "Sink Faucet",
          "nicknames": [
            "Faucet"
          ]
        },
        "willReportState": true,
        "attributes": {
          "supportedDispenseItems": [
            {
              "item_name": "water",
              "item_name_synonyms": [
                {
                  "lang": "en",
                  "synonyms": [
                    "water"
                  ]
                },
                {
                  "lang": "es",
                  "synonyms": [
                    "agua"
                  ]
                },
                {
                  "lang": "fr",
                  "synonyms": [
                    "eau"
                  ]
                }
              ],
              "supported_units": [
                "TEASPOONS",
                "TABLESPOONS",
                "FLUID_OUNCES",
                "CUPS",
                "PINTS",
                "QUARTS",
                "GALLONS",
                "MILLILITERS",
                "LITERS",
                "DECILITERS"
              ],
              "default_portion": {
                "amount": 2,
                "unit": "CUPS"
              }
            }
          ],
          "supportedDispensePresets": [
            {
              "preset_name": "cat water bowl",
              "preset_name_synonyms": [
                {
                  "lang": "en",
                  "synonyms": [
                    "cat water bowl",
                    "cat water dish",
                    "cat water cup"
                  ]
                },
                {
                  "lang": "es",
                  "synonyms": [
                    "plato de agua para gato",
                    "bebedero para gato"
                  ]
                },
                {
                  "lang": "fr",
                  "synonyms": [
                    "bol d'eau de chat",
                    "bac à eau pour chat",
                    "tasse d'eau de chat"
                  ]
                }
              ]
            }
          ]
        },
        "customData": {
          "fooValue": 42,
          "barValue": true,
          "catValue": "Fuzzy"
        }
      }
    ]
  }
}
Validator

Device STATES

State Definition
dispenseItems Optional array of objects. Contains state information on all items that the device can dispense, including the following details for each object:
  • itemName: Optional string. The value of an item_name from the supportedDispenseItems attribute (for example, "water", "dog treats", or "cat food").
  • amountRemaining: Optional object. Indicates the amount of that item remaining in the device. If the device is currently dispensing, this reports the remaining amount or what the amount will be once the device finishes dispensing.
    • amount: Float.
    • unit: String.
  • amountLastDispensed: Optional object. Indicates the amount of that item that the device most recently dispensed. If the device is currently dispensing, this should report the amount it dispensed prior to the current dispensing amount.
    • amount: Float.
    • unit: String.
  • isCurrentlyDispensing: Optional boolean. Indicates if the device is currently dispensing this item.

amountRemaining and amountLastDispensed only need to be reported using one unit of measurement.

Multiple items can be provided within the dispenseItems array. Each item name must be unique and must correspond to an item in the supportedDispenseItems attribute.

Example of the device state format:

{
  "states": {
    "dispenseItems": [{
      "itemName": "STRING",
      "amountRemaining": {
        "amount": "FLOAT",
        "unit": "STRING"
      },
      "amountLastDispensed": {
        "amount": "FLOAT",
        "unit": "STRING"
      },
      "isCurrentlyDispensing": "BOOL"
    }]
  }
}

Sample QUERY Request and Response

UserHow many dog treats are remaining in my dispenser?
Assistant<device name> has 83 dog treats remaining.
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: {
          online: true,
          dispenseItems: [{
            itemName: 'dog treats',
            amountRemaining: {
              amount: 83.0,
              unit: 'NO_UNITS'
            },
            amountLastDispensed: {
              amount: 2.0,
              unit: 'NO_UNITS'
            },
            isCurrentlyDispensing: false
          }]
        },
        status: 'SUCCESS'
      }
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
Java
put("dispenseItems", new HashMap[] {
    new HashMap<String, Object>() {{        put("itemName", "dog treats");
        put("amountRemaining", new HashMap<String, Object>() {{            put("amount", 83.0);
            put("units", "NO_UNITS");
        }});
        put("amountLastDispensed", new HashMap<String, Object>() {{            put("amount", 2.0);
            put("unit", "NO_UNITS");
        }});
        put("isCurrentlyDispensing", false);
    }}});
JSON
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "devices": {
      "123": {
        "online": true,
        "dispenseItems": [
          {
            "itemName": "dog treats",
            "amountRemaining": {
              "amount": 83,
              "unit": "NO_UNITS"
            },
            "amountLastDispensed": {
              "amount": 2,
              "unit": "NO_UNITS"
            },
            "isCurrentlyDispensing": false
          }
        ]
      },
      "status": "SUCCESS"
    }
  }
}
UserHow much water is remaining in my water cooler?
Assistant< device name> has 6.2 gallons of water remaining.
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: {
          online: true,
          dispenseItems: [{
            itemName: 'water',
            amountRemaining: {
              amount: 6.2,
              unit: 'GALLONS'
            },
            amountLastDispensed: {
              amount: 1.0,
              unit: 'CUPS'
            },
            isCurrentlyDispensing: false
          }]
        },
        status: 'SUCCESS'
      }
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
Java
put("dispenseItems", new HashMap[] {
    new HashMap<String, Object>() {{        put("itemName", "water");
        put("amountRemaining", new HashMap<String, Object>() {{            put("amount", 6.2);
            put("units", "GALLONS");
        }});
        put("amountLastDispensed", new HashMap<String, Object>() {{            put("amount", 1.0);
            put("unit", "CUPS");
        }});
        put("isCurrentlyDispensing", false);
    }}});
JSON
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "devices": {
      "123": {
        "online": true,
        "dispenseItems": [
          {
            "itemName": "water",
            "amountRemaining": {
              "amount": 6.2,
              "unit": "GALLONS"
            },
            "amountLastDispensed": {
              "amount": 1,
              "unit": "CUPS"
            },
            "isCurrentlyDispensing": false
          }
        ]
      },
      "status": "SUCCESS"
    }
  }
}
UserHow much cat food did I give before?
Assistant<device name> last dispensed 2.5 cups of cat food.
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: {
          online: true,
          dispenseItems: [{
            itemName: 'cat food',
            amountRemaining: {
              amount: 16.5,
              unit: 'CUPS'
            },
            amountLastDispensed: {
              amount: 2.5,
              unit: 'CUPS'
            },
            isCurrentlyDispensing: false
          }]
        },
        status: 'SUCCESS'
      }
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
Java
put("dispenseItems", new HashMap[] {
    new HashMap<String, Object>() {{        put("itemName", "cat food");
        put("amountRemaining", new HashMap<String, Object>() {{            put("amount", 16.5);
            put("units", "CUPS");
        }});
        put("amountLastDispensed", new HashMap<String, Object>() {{            put("amount", 2.5);
            put("unit", "CUPS");
        }});
        put("isCurrentlyDispensing", false);
    }}});
JSON
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "devices": {
      "123": {
        "online": true,
        "dispenseItems": [
          {
            "itemName": "cat food",
            "amountRemaining": {
              "amount": 16.5,
              "unit": "CUPS"
            },
            "amountLastDispensed": {
              "amount": 2.5,
              "unit": "CUPS"
            },
            "isCurrentlyDispensing": false
          }
        ]
      },
      "status": "SUCCESS"
    }
  }
}
UserIs the faucet still dispensing water?
AssistantThe faucet is currently dispensing water.
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: {
          online: true,
          dispenseItems: [{
            itemName: 'water',
            isCurrentlyDispensing: true
          }]
        },
        status: 'SUCCESS'
      }
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
Java
put("dispenseItems", new HashMap[] {
    new HashMap<String, Object>() {{        put("itemName", "water");
        put("isCurrentlyDispensing", true);
    }}});
JSON
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "devices": {
      "123": {
        "online": true,
        "dispenseItems": [
          {
            "itemName": "water",
            "isCurrentlyDispensing": true
          }
        ]
      },
      "status": "SUCCESS"
    }
  }
}

Device COMMANDS

Command Parameters/Definition
action.devices.commands.Dispense

This command supports dispensing items by a given amount or preset, or without parameters.

Specification Type Parameters
Amount
  • amount: Required float.
  • unit: Required string from set of supported units.
  • item: Optional string from reported supported items.
Preset presetName: Required string from reported supported presets.
Generic If the user requests to dispense from the device without providing any presets or items, no parameters are provided.

Sample EXECUTE Request and Response

UserDispense 3 cups of cat food.
AssistantSure, dispensing 3 cups of cat food from the pet feeder.
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.Dispense",
          "params": {
            "amount": 3.0,
            "unit": "CUPS",
            "item": "cat food"
          }
        }]
      }]
    }
  }]
}
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: {
              dispenseItems: [{
                itemName: 'cat food',
                amountRemaining: {
                  amount: 17.0,
                  unit: 'CUPS'
                },
                amountLastDispensed: {
                  amount: 3.0,
                  unit: 'CUPS'
                },
                isCurrentlyDispensing: true
              }]
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('dispense_execute_2', function() {
    const executeRequest =
    {
      "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.Dispense",
              "params": {
                "amount": 3.0,
                "unit": "NO_UNITS",
                "item": "dog treats"
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {
              dispenseItems: [{
                itemName: 'dog treats',
                amountRemaining: {
                  amount: 27.0,
                  unit: 'NO_UNITS'
                },
                amountLastDispensed: {
                  amount: 3.0,
                  unit: 'NO_UNITS'
                },
                isCurrentlyDispensing: true
              }]
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('dispense_execute_3', function() {
    const executeRequest =
    {
      "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.Dispense",
                    "params": {
                      "amount": 1.0,
                      "unit": "CUPS",
                      "item": "water"
                    }
                  }
                ]
              }
            ]
          }
        }
      ]
    }
    ;
    '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: {
              dispenseItems: [{
                itemName: 'water',
                amountLastDispensed: {
                  amount: 1.0,
                  unit: 'CUPS'
                },
                isCurrentlyDispensing: true
              }]
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('dispense_execute_4', function() {
    const executeRequest =
    {
      "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.Dispense",
              "params": {
                "presetName": "cat food bowl"
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {
              dispenseItems: [{
                itemName: 'cat food',
                amountLastDispensed: {
                  amount: 14.5,
                  unit: 'CUPS'
                },  
                isCurrentlyDispensing: true
              }]
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  /*
   * action.devices.traits.Dock
   * http://developers.google.com/actions/smarthome/traits/dock
   */
  it('dock_sync', function() {
'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.VACUUM',
        traits: [
          'action.devices.traits.Dock'
        ],
        name: {
          defaultNames: ['AAA Cybernetics Corp Vacuum'],
          name: 'vacuum',
          nicknames: []
        },
        willReportState: true,
        deviceInfo: {
          manufacturer: 'sirius',
          model: '442',
          hwVersion: '3.2',
          swVersion: '11.4'
        },
        customData: {
          fooValue: 74,
          barValue: true,
          bazValue: 'lambtwirl'
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('dock_query', function() {
'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: {
          online: true,
          isDocked: true
        },
        status: 'SUCCESS'
      }
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('dock_execute', function() {
    const executeRequest =
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "inputs": [{
    "intent": "action.devices.EXECUTE",
    "payload": {
      "commands": [{
        "devices": [{
          "id": "123",
          "customData": {
            "fooValue": 74,
            "barValue": true,
            "bazValue": "sheepdip"
          }
        }],
        "execution": [{
          "command": "action.devices.commands.Dock"
        }]
      }]
    }
  }]
}
    ;
'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: {
            isDocked: true
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(executeRequest);
  });

    /*
   * action.devices.traits.FanSpeed
   * http://developers.google.com/actions/smarthome/traits/fanspeed
   */
  it('fanspeed_sync', function() {
'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.FAN',
        traits: [
          'action.devices.traits.FanSpeed'
        ],
        name: {
          defaultNames: ['Sirius Cybernetics Corporation 33321'],
          name: 'Fan',
          nicknames: ['wall fan']
        },
        willReportState: true,
        attributes: {
          availableFanSpeeds: {
            speeds: [{
              speed_name: 'Low',
              speed_values: [{
                speed_synonym: ['low', 'slow'],
                lang: 'en'
              }, {
                speed_synonym: ['low', 'slow'],
                lang: 'de'
              }]
            }, {
              speed_name: 'High',
              speed_values: [{
                speed_synonym: ['high'],
                lang: 'en'
              }, {
                speed_synonym: ['high'],
                lang: 'de'
              }]
            }],
            ordered: true
          },
          reversible: true
        },
        deviceInfo: {
          manufacturer: 'Sirius Cybernetics Corporation',
          model: '233451',
          hwVersion: '3.2',
          swVersion: '11.4'
        },
        customData: {
          fooValue: 74,
          barValue: true,
          bazValue: 'lambtwirl'
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('fanspeed_query', function() {
'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,
          currentFanSpeedSetting: 'S2'
        },
        456: {
          on: true,
          online: true,
          currentFanSpeedSetting: 'S1'
        },
        status: 'SUCCESS'
      }
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('fanspeed_execute_1', function() {
    const executeRequest =
{
  "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.SetFanSpeed",
          "params": {
            "fanSpeed": "S1"
          }
        }]
      }]
    }
  }]
}
    ;
'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: {
          currentFanSpeedSetting: 'S1'
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('fanspeed_execute_2', function() {
    const executeRequest =
{
  "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.SetFanSpeed",
          "params": {
            "fanSpeed": "S2"
          }
        }]
      }]
    }
  }]
}
    ;
'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: {
          currentFanSpeedSetting: 'S2'
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  /*
   * action.devices.traits.Fill
   * https://devsite.googleplex.com/actions/smarthome/traits/eap/fill
   */
  it('fill_sync', function() {
    '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.BATHTUB',
            traits: [
              'action.devices.traits.OnOff',
              'action.devices.traits.Fill'
            ],
            name: {
              defaultNames: ['Smart Tub'],
              name: 'Tub',
              nicknames: ['Master Bathtub', 'Rubber Duck Pond']
            },
            willReportState: true,
            attributes: {
              availableFillLevels: {
                levels: [{
                  level_name: 'half_key',
                  level_values: [{
                    level_synonym: ['half', 'halfway', 'one half'],
                    lang: 'en'
                  }]
                }],
                ordered: true
              }
            },
            deviceInfo: {
              manufacturer: 'Sirius Cybernetics Corporation',
              model: '492134',
              hwVersion: '3.2',
              swVersion: '11.4'
            },
            customData: {
              fooValue: 74,
              barValue: true,
              bazValue: 'lambtwirl'
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('fill_query', function() {
    '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,
              currentFillLevel: 'half',
              isFilled: true
            },
            status: 'SUCCESS'
          }
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('fill_execute', function() {
    const executeRequest =
    {
      "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.Fill",
              "params": {
                "fill": true,
                "fillLevel": "half"
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {
              currentFillLevel: 'half',
              isFilled: true
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  /*
   * action.devices.traits.HumiditySetting
   * https://devsite.googleplex.com/actions/smarthome/traits/eap/humiditysetting
   */
  it('humiditysetting_sync', function() {
    '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.HUMIDIFIER',
            traits: [
              'action.devices.traits.StartStop',
              'action.devices.traits.FanSpeed',
              'action.devices.traits.HumiditySetting'
            ],
            name: {
              defaultNames: ['Sirius Cybernetics Corporation Humidifer'],
              name: 'Humidifier',
              nicknames: ['Bedroom Humidifier']
            },
            roomHint: 'Bedroom',
            willReportState: true,
            attributes: {
              pausable: true,
              availableFanSpeeds: {
                speeds: [{
                  speed_name: 'Low',
                  speed_values: [{
                    speed_synonym: ['low', 'slow'],
                    lang: 'en'
                  }, {
                    speed_synonym: ['niedrig', 'schleppend'],
                    lang: 'de'
                  }]
                }, {
                  speed_name: 'High',
                  speed_values: [{
                    speed_synonym: ['high'],
                    lang: 'en'
                  }, {
                    speed_synonym: ['hoch'],
                    lang: 'de'
                  }]
                }],
                ordered: true
              },
              reversible: true,
              humiditySetpointRange: {
                minPercent: 30,
                maxPercent: 100
              }
            },
            deviceInfo: {
              manufacturer: 'Sirius Cybernetics Corporation',
              model: '8675309',
              hwVersion: '3.2',
              swVersion: '11.4'
            },
            customData: {
              fooValue: 74,
              barValue: true,
              bazValue: 'goatjive'
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('humiditysetting_query', function() {
    '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: {
              humiditySetpointPercent: 20,
              humidityAmbientPercent: 15
            },
            status: 'SUCCESS'
          }
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('humiditysetting_execute', function() {
    const executeRequest =
    {
      "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.SetHumidity",
              "params": {
                "humidity": 20
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {
              humiditySetpointPercent: 20,
              humidityAmbientPercent: 15
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  /*
   * action.devices.traits.InputSelector
   * https://devsite.googleplex.com/actions/smarthome/traits/eap/inputselector
   */
  it('inputselector_sync', function() {
    '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.TV',
            traits: [
              'action.devices.traits.OnOff',
              'action.devices.traits.InputSelector'
            ],
            name: {
              defaultNames: ['television'],
              name: 'Livingroom Television',
              nicknames: ['tv']
            },
            willReportState: true,
            attributes: {
              availableInputs: [{
                key: 'hdmi_1',
                names: [{
                  name_synonym: ['hdmi 1', '1st hdmi'],
                  lang: 'en'
                }, {
                  name_synonym: ['hdml 1', 'zuerst hdmi'],
                  lang: 'de'
                }]
              }, {
                key: 'usb_1',
                names: [{
                  name_synonym: ['usb 1', '1st usb'],
                  lang: 'en'
                }]
              }],
              orderedInputs: true
            },
            customData: {
              fooValue: 74,
              barValue: true,
              bazValue: 'foo bar'
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('inputselector_query', function() {
    '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,
              currentInput: 'hdmi_1'
            },
            status: 'SUCCESS'
          }
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('inputselector_execute', function() {
    const executeRequest =
    {
      "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.SetInput",
              "params": {
                "newInput": "hdmi_1"
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {
              currentInput: 'hdmi_1'
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  /*
   * action.devices.traits.LightEffects
   * http://developers.google.com/actions/smarthome/traits/lighteffects
   */
  it('lighteffects_sync', function() {
    '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.LIGHT',
            traits: [
              'action.devices.traits.OnOff',
              'action.devices.traits.LightEffects'
            ],
            name: {
              defaultNames: ['AAA bulb A19 color hyperglow'],
              name: 'Lamp',
              nicknames: ['Reading lamp']
            },
            willReportState: true,
            attributes: {
              supportedEffects: [
                'colorLoop',
                'sleep',
                'wake'
              ],
            },
            deviceInfo: {
              manufacturer: 'BrandX',
              model: 'hg11',
              hwVersion: '1.2',
              swVersion: '5.4'
            },
            customData: {
              fooValue: 12,
              barValue: false,
              bazValue: 'goatjive'
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('lighteffects_query', function() {
    '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,
              activeLightEffect: 'colorLoop',
              online: true
            },
            status: 'SUCCESS'
          }
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('lighteffects_execute_1', function() {
    const executeRequest =
    {
      "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
      "inputs": [{
        "intent": "action.devices.EXECUTE",
        "payload": {
          "commands": [{
            "devices": [{
              "id": "123",
              "customData": {
                "fooValue": 74,
                "barValue": true,
                "bazValue": "goatjive"
              }
            }],
            "execution": [{
              "command": "action.devices.commands.ColorLoop"
            }]
          }]
        }
      }]
    }
    ;
    '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: {
              on: true,
              activeLightEffect: 'colorLoop'
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('lighteffects_execute_2', function() {
    const executeRequest =
    {
      "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
      "inputs": [{
        "intent": "action.devices.EXECUTE",
        "payload": {
          "commands": [{
            "devices": [{
              "id": "123",
              "customData": {
                "fooValue": 74,
                "barValue": true,
                "bazValue": "goatjive"
              }
            }],
            "execution": [{
              "command": "action.devices.commands.Sleep",
              "params": {
                "duration": 1800
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {
              on: true,
              activeLightEffect: 'sleep'
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('lighteffects_execute_3', function() {
    const executeRequest =
    {
      "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
      "inputs": [{
        "intent": "action.devices.EXECUTE",
        "payload": {
          "commands": [{
            "devices": [{
              "id": "123",
              "customData": {
                "fooValue": 74,
                "barValue": true,
                "bazValue": "goatjive"
              }
            }],
            "execution": [{
              "command": "action.devices.commands.Wake",
              "params": {
                "duration": 1800
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {
              on: true,
              activeLightEffect: 'wake'
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  /*
   * action.devices.traits.Locator
   * http://developers.google.com/actions/smarthome/traits/locator
   */
  it('locator_sync', function() {
'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.VACUUM',
        traits: [
          'action.devices.traits.Locator'
        ],
        name: {
          defaultNames: ['Smart Vacuum'],
          name: 'SmartVac',
          nicknames: ['Vac']
        },
        willReportState: true,
        deviceInfo: {
          manufacturer: 'Smart Home Provider',
          model: 'g1340',
          swVersion: '1.0.31',
          hwVersion: '1.1'
        },
        customData: {
          smartHomeProviderId: 'fiGgZ0vrhFRgwf5XJkna2GRwO8z80J'
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('locator_execute', function() {
    const executeRequest =
{
  "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.Locate",
          "params": {
            "silence": false,
            "lang": "en"
          }
        }]
      }]
    }
  }]
}
    ;
'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: {
          generatedAlert: true
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  /*
   * action.devices.traits.LockUnlock
   * https://devsite.googleplex.com/actions/smarthome/traits/eap/lockunlock
   */
  it('lockunlock_sync', function() {
    '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.LOCK',
            traits: [
              'action.devices.traits.LockUnlock'
            ],
            name: {
              defaultNames: ['Sirius Cybernetics Corporation 33321'],
              name: 'Lock',
              nicknames: ['front door']
            },
            willReportState: true,
            deviceInfo: {
              manufacturer: 'Sirius Cybernetics Corporation',
              model: '492135',
              hwVersion: '3.2',
              swVersion: '11.4'
            },
            customData: {
              fooValue: 74,
              barValue: true,
              bazValue: 'lambtwirl'
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('lockunlock_query', function() {
    '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
            },
            456: {
              online: true,
              isLocked: true,
              isJammed: false
            },
            status: 'SUCCESS'
          }
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('lockunlock_execute', function() {
    const executeRequest =
    {
      "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.LockUnlock",
              "params": {
                "lock": true
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {
              isLocked: true,
              isJammed: false
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  /*
   * action.devices.traits.Modes
   * http://developers.google.com/actions/smarthome/traits/modes
   */
  it('modes_sync', function() {
'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.WASHER',
        traits: [
          'action.devices.traits.Modes'
        ],
        name: {
          defaultNames: ['AAA Cybernetics Corporation Washer 3421'],
          name: 'Washer',
          nicknames: ['clothes washer']
        },
        willReportState: true,
        attributes: {
          availableModes: [{
            name: 'load',
            name_values: [{
              name_synonym: ['load', 'size', 'load size'],
              lang: 'en'
            }],
            settings: [{
              setting_name: 'small',
              setting_values: [{
                setting_synonym: ['small', 'half'],
                lang: 'en'
              }]
            }, {
              setting_name: 'large',
              setting_values: [{
                setting_synonym: ['large', 'full'],
                lang: 'en'
              }]
            }],
            ordered: true
          }]
        },
        deviceInfo: {
          manufacturer: 'AAA Cybernetics Corporation',
          model: '233451',
          hwVersion: '3.2',
          swVersion: '11.4'
        },
        customData: {
          fooValue: 74,
          barValue: true,
          bazValue: 'lambtwirl'
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('modes_query', function() {
'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,
          currentModeSettings: {
            drytype: 'permpress',
            load: 'large'
          }
        },
        456: {
          on: true,
          online: true,
          isPaused: true,
          isRunning: false,
          currentModeSettings: {
            temperature: 'hot',
            load: 'large'
          }
        },
        status: 'SUCCESS'
      }
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('modes_execute', function() {
    const executeRequest =
{
  "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.SetModes",
          "params": {
            "updateModeSettings": {
              "drytype": "permpress"
            }
          }
        }]
      }]
    }
  }]
}
    ;
'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: {
           currentModeSettings: {
             drytype: 'permpress',
             load: 'large'
           }
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  /*
   * action.devices.traits.NetworkControl
   * https://devsite.googleplex.com/actions/smarthome/traits/eap/networkcontrol
   */
  it('networkcontrol_sync', function() {
    '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.ROUTER',
            traits: [
              'action.devices.traits.Reboot',
              'action.devices.traits.SoftwareUpdate',
              'action.devices.traits.NetworkControl',
              'action.devices.traits.Modes',
              'action.devices.traits.Toggles'
            ],
            name: {
              defaultNames: ['Sirius Cybernetics Router 2331'],
              name: 'Router',
              nicknames: ['Upstairs Router']
            },
            willReportState: true,
            attributes: {
              supportsGuestNetwork: true,
              availableToggles: [{
                name: 'Power Saver Mode',
                values: [{
                  name_synonym: ['Power Saver', 'Low Power Mode'],
                  lang: 'en'
                }]
              }],
              availableModes: [{
                name: 'Parental Control',
                name_values: [{
                  name_synonym: ['Parental Restriction', 'Restriction'],
                  lang: 'en'
                }],
                settings: [{
                  setting_name: 'off',
                  setting_values: [{
                    setting_synonym: ['Paused'],
                    lang: 'en'
                  }]
                }, {
                  setting_name: 'High',
                  setting_values: [{
                    setting_synonym: ['High'],
                    lang: 'en'
                  }]
                }],
                ordered: true
              }]
            },
            deviceInfo: {
              manufacturer: 'Sirius Cybernetics',
              model: '2331B',
              hwVersion: '11.2',
              swVersion: '11.4'
            },
            customData: {
              fooValue: 74,
              barValue: true,
              bazValue: 'lambtwirl'
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('networkcontrol_query', function() {
    '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,
              networkEnabled: true,
              networkSettings: {
                ssid: 'home-network-123',
                password: 'home-password-123'
              },
              numConnectedDevices: 4,
              networkSpeedMbps: 100.8
            },
            status: 'SUCCESS'
          }
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('networkcontrol_execute_1', function() {
    // Turn on the Internet
    const executeRequest =
    {
      "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.EnableDisableNetwork",
              "params": {
                "enable": true
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {
              networkEnabled: true
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('networkcontrol_execute_2', function() {
    // Turn on the guest network
    const executeRequest =
    {
      "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.EnableDisableGuestNetwork",
              "params": {
                "enable": true
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {
              guestNetworkEnabled: true
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('networkcontrol_execute_3', function() {
    // Disabled a network profile
    const executeRequest =
    {
      "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.EnableDisableNetworkProfile",
              "params": {
                "profile": "Lucas",
                "enable": false
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {
              guestNetworkEnabled: true
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('networkcontrol_execute_4', function() {
    // Turn on the guest network
    const executeRequest =
    {
      "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.ScanNetwork",
              "params": {
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {}
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  /*
   * action.devices.traits.OnOff
   * http://developers.google.com/actions/smarthome/traits/onoff
   */
  it('onoff_sync', function() {
'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.LIGHT',
        traits: [
          'action.devices.traits.OnOff'
        ],
        name: {
          defaultNames: ['AAA bulb A19 color hyperglow'],
          name: 'lamp1',
          nicknames: ['reading lamp']
        },
        willReportState: true,
        attributes: {
          commandOnlyOnOff: false
        },
        deviceInfo: {
          manufacturer: 'BrandX',
          model: 'hg11',
          hwVersion: '1.2',
          swVersion: '5.4'
        },
        customData: {
          fooValue: 12,
          barValue: false,
          bazValue: 'dancing alpaca'
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('onoff_query', function() {
'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
        },
        456: {
          on: false,
          online: true
        },
        status: 'SUCCESS'
      }
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('onoff_execute', function() {
    const executeRequest =
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "inputs": [{
    "intent": "action.devices.EXECUTE",
    "payload": {
      "commands": [{
        "devices": [{
          "id": "123",
          "customData": {
            "fooValue": 74,
            "barValue": true,
            "bazValue": "sheepdip"
          }
        }, {
          "id": "456",
          "customData": {
            "fooValue": 36,
            "barValue": false,
            "bazValue": "moarsheep"
          }
        }],
        "execution": [{
          "command": "action.devices.commands.OnOff",
          "params": {
            "on": true
          }
        }]
      }]
    }
  }]
}
    ;
'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: {
          on: true,
          online: true
        }
      }, {
        ids: ['456'],
        status: 'ERROR',
        errorCode: 'deviceTurnedOff'
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  /*
   * action.devices.traits.Reboot
   * https://devsite.googleplex.com/actions/smarthome/traits/eap/reboot
   */
  it('reboot_sync', function() {
    '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.LIGHT',
            traits: [
              'action.devices.traits.OnOff',
              'action.devices.traits.Reboot',
            ],
            name: {
              defaultNames: ['Sirius Cybernetics Light 2331'],
              name: 'Light',
              nicknames: ['Upstairs Light']
            },
            willReportState: true,
            deviceInfo: {
              manufacturer: 'Sirius Cybernetics',
              model: '2331B',
              hwVersion: '11.2',
              swVersion: '11.4'
            },
            customData: {
              fooValue: 2019,
              barValue: true,
              bazValue: 'goatjive'
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('reboot_execute', function() {
    const executeRequest =
    {
      "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.Reboot",
              "params": {
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {}
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  /*
   * action.devices.traits.Rotation
   * https://devsite.googleplex.com/actions/smarthome/traits/eap/rotation
   */
  it('rotation_sync', function() {
    '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.Rotation'
            ],
            name: {
              defaultNames: ['Blinds window'],
              name: 'Kitchen window',
              nicknames: ['Sink window']
            },
            willReportState: true,
            attributes: {
              supportsDegrees: true,
              supportsPercent: true,
              rotationDegreesRange: {
                rotationDegreesMin: 0.0,
                rotationDegreesMax: 180.0
              }
            },
            deviceInfo: {
              manufacturer: 'AAA',
              model: 'xyz',
              hwVersion: '3.2',
              swVersion: '11.4'
            },
            customData: {
              fooValue: 74,
              barValue: true,
              bazValue: 'lambtwirl'
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('rotation_query_1', function() {
    '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: {
              online: true,
              rotationPercent: 25.0
            },
            status: 'SUCCESS'
          }
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('rotation_query_2', function() {
    '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: {
              online: true,
              rotationDegrees: 90.0
            },
            status: 'SUCCESS'
          }
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('rotation_execute_1', function() {
    const executeRequest =
    {
      "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.RotateAbsolute",
              "params": {
                "rotationPercent": 50.0
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {
              rotationPercent: 50.0
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('rotation_execute_2', function() {
    const executeRequest =
    {
      "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.RotateAbsolute",
              "params": {
                "rotationDegrees": 15.0
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {
              rotationDegrees: 15.0,
              online: true
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  /*
   * action.devices.traits.RunCycle
   * http://developers.google.com/actions/smarthome/traits/runcycle
   */
  it('runcycle_sync', function() {
'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.DRYER',
        traits: [
          'action.devices.traits.RunCycle'
        ],
        name: {
          defaultNames: ['AAA Super Dryer'],
          name: 'Washer',
          nicknames: ['clothes dryer']
        },
        willReportState: true,
        deviceInfo: {
          manufacturer: 'AAA Corporation',
          model: '492134',
          hwVersion: '3.2',
          swVersion: '11.4'
        },
        customData: {
          fooValue: 74,
          barValue: true,
          bazValue: 'lambtwirl'
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('runcycle_query', function() {
'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: {
          currentRunCycle: [{
            currentCycle: 'rinse',
            nextCycle: 'spin',
            lang: 'en'
          }],
          currentTotalRemainingTime: 1212,
          currentCycleRemainingTime: 301
        },
        status: 'SUCCESS'
      }
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  /*
   * action.devices.traits.Scene
   * http://developers.google.com/actions/smarthome/traits/scene
   */
  it('scene_sync', function() {
'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.SCENE',
        traits: [
          'action.devices.traits.Scene'
        ],
        name: {
          defaultNames: [],
          name: 'Party Mode',
          nicknames: []
        },
        willReportState: true, // should be false, as there's no state
        attributes: {
          sceneReversible: true
        },
        // Note -- probably no device info for virtual devices.
        customData: {
          fooValue: 74,
          barValue: true,
          bazValue: 'lambtwirl'
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('scene_query', function() {
'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: {
          online: true
        },
        status: 'SUCCESS'
      }
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('scene_execute', function() {
    const executeRequest =
{
  "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.ActivateScene",
          "params": {
            "deactivate": false
          }
        }]
      }]
    }
  }]
}
    ;
'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: {
          // Note -- scenes are stateless.
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  /*
   * action.devices.traits.SensorState
   * https://devsite.googleplex.com/actions/smarthome/traits/eap/sensorstate
   */
  it('sensorstate_sync', function() {
    '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.SENSOR',
            traits: [
              'action.devices.traits.SensorState'
            ],
            name: {
              defaultNames: ['Default sensor name'],
              name: 'Front door',
              nicknames: ['front door sensor']
            },
            attributes: {
              sensorStatesSupported: [{
                name: "CarbonMonoxideLevel",
                descriptiveCapabilities: {
                  availableStates: ['carbon monoxide detected', 'high', 'no carbon monoxide detected', 'unknown'],
                  trackHistory: false
                },
                numericCapabilities: {
                  rawValueUnit: 'PARTS_PER_MILLION'
                }
              }]
            },
            deviceInfo: {
              manufacturer: 'nest',
              model: 'c110',
              hwVersion: '3.2',
              swVersion: '11.4'
            },
            customData: {
              fooValue: 42,
              barValue: true,
              bazValue: 'sheepdip'
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('sensorstate_query', function() {
    '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,
              currentSensorStateData: [{
                name: 'CarbonMonoxideLevel',
                currentSensorState: 'high',
                rawValue: 100.0
              }]
            },
            status: 'SUCCESS'
          }
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  /*
   * action.devices.traits.SoftwareUpdate
   * https://devsite.googleplex.com/actions/smarthome/traits/eap/softwareupdate
   */
  it('softwareupdate_sync', function() {
    '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.LIGHT',
            traits: [
              'action.devices.traits.OnOff',
              'action.devices.traits.SoftwareUpdate',
            ],
            name: {
              defaultNames: ['Sirius Cybernetics Light 2331'],
              name: 'Light',
              nicknames: ['Upstairs Light']
            },
            willReportState: true,
            deviceInfo: {
              manufacturer: 'Sirius Cybernetics',
              model: '2331B',
              hwVersion: '11.2',
              swVersion: '11.4'
            },
            customData: {
              fooValue: 2019,
              barValue: true,
              bazValue: 'goatjive'
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('softwareupdate_query', function() {
    '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,
              lastSoftwareUpdateUnixTimestampSec: 1542059207
            },
            status: 'SUCCESS'
          }
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('softwareupdate_execute', function() {
    const executeRequest =
    {
      "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.SoftwareUpdate",
              "params": {
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {}
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  /*
   * action.devices.traits.StartStop
   * http://developers.google.com/actions/smarthome/traits/startstop
   */
  it('startstop_sync', function() {
    '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.WASHER',
            traits: [
              'action.devices.traits.StartStop'
            ],
            name: {
              defaultNames: ['Sirius Cybernetics Corporation Washer 3421'],
              name: 'Washer',
              nicknames: ['clothes washer']
            },
            willReportState: true,
            attributes: {
              pausable: true,
              availableZones: ['kitchen', 'living room', 'master bedroom']
            },
            deviceInfo: {
              manufacturer: 'AAA Cybernetics Corporation',
              model: '233451',
              hwVersion: '3.2',
              swVersion: '11.4'
            },
            customData: {
              fooValue: 74,
              barValue: true,
              bazValue: 'lambtwirl'
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('startstop_query', function() {
    '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: {
              online: true,
              isPaused: true,
              isRunning: false,
              activeZones: ['kitchen']
            },
            status: 'SUCCESS'
          }
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('startstop_execute_1', function() {
    const executeRequest =
    {
      "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
      "inputs": [{
        "intent": "action.devices.EXECUTE",
        "payload": {
          "commands": [{
            "devices": [{
              "id": "123",
              "customData": {
                "fooValue": 74,
                "barValue": true,
                "bazValue": "sheepdip"
              }
            }],
            "execution": [{
              "command": "action.devices.commands.StartStop",
              "params": {
                "start": true
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {
              isRunning: true,
              isPaused: false
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('startstop_execute_2', function() {
    const executeRequest =
    {
      "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
      "inputs": [{
        "intent": "action.devices.EXECUTE",
        "payload": {
          "commands": [{
            "devices": [{
              "id": "123",
              "customData": {
                "fooValue": 74,
                "barValue": true,
                "bazValue": "sheepdip"
              }
            }],
            "execution": [{
              "command": "action.devices.commands.StartStop",
              "params": {
                "start": true,
                "zone": "kitchen"
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {
              isRunning: true,
              isPaused: false,
              activeZones: ['kitchen']
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('startstop_execute_3', function() {
    const executeRequest =
    {
      "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
      "inputs": [{
        "intent": "action.devices.EXECUTE",
        "payload": {
          "commands": [{
            "devices": [{
              "id": "123",
              "customData": {
                "fooValue": 74,
                "barValue": true,
                "bazValue": "sheepdip"
              }
            }],
            "execution": [{
              "command": "action.devices.commands.PauseUnpause",
              "params": {
                "pause": true
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {
              isRunning: true,
              isPaused: true
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  /*
   * action.devices.traits.StatusReport
   * https://developers.google.com/actions/smarthome/traits/statusreport
   */
  it('statusreport_sync', function() {
    '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.SECURITYSYSTEM',
            traits: [
              'action.devices.traits.StatusReport'
            ],
            name: {
              defaultNames: ['Sirius Cybernetics Corp Security System'],
              name: 'Security system',
              nicknames: ['Security system']
            },
            willReportState: true,
            attributes: {},
            deviceInfo: {
              manufacturer: 'Sirius Cybernetics Corporation',
              model: '442',
              hwVersion: '3.2',
              swVersion: '11.4'
            },
            customData: {
              fooValue: 74,
              barValue: true,
              bazValue: 'lambtwirl'
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('statusreport_query', function() {
    '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,
              currentStatusReport: [{
                blocking: false,
                deviceTarget: '123',
                priority: 0,
                statusCode: 'lowBattery'
              }, {
                blocking: false,
                deviceTarget: 'front_window_id',
                priority: 1,
                statusCode: 'deviceOpen'
              }, {
                blocking: false,
                deviceTarget: 'back_window_id',
                priority: 1,
                statusCode: 'deviceOpen'
              }]
            },
            status: 'SUCCESS'
          }
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  /*
   * action.devices.traits.EnergyStorage
   * https://developers.google.com/assistant/smarthome/traits/energystorage
   */
  it('energystorage_sync_1', function() {
    'use strict';

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

    const app = smarthome();

    app.onSync((body, headers) => {
      return {
        requestId: "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
        payload: {
          agentUserId: "1836.15267389",
          devices: [{
            id: "123",
            type: "action.devices.types.CHARGER",
            traits: [
              "action.devices.traits.EnergyStorage"
            ],
            name: {
              defaultNames: [],
              name: "Rechargable Gizmo",
              nicknames: []
            },
            willReportState: true,
            attributes: {
              isRechargeable: true,
              queryOnlyEnergyStorage: false
            },
            deviceInfo: {
              manufacturer: "ACME Inc.",
              model: "GIZMO-R",
              hwVersion: "PVT-2",
              swVersion: "1.0.1"
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('energystorage_sync_2', function() {
    'use strict';

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

    const app = smarthome();

    app.onSync((body, headers) => {
      return {
        requestId: "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
        payload: {
          agentUserId: "1836.15267389",
          devices: [{
            id: "123",
            type: "action.devices.types.CHARGER",
            traits: [
              "action.devices.traits.EnergyStorage"
            ],
            name: {
              defaultNames: [],
              name: "Rechargable Vehicle",
              nicknames: []
            },
            willReportState: true,
            attributes: {
              isRechargeable: true,
              energyStorageDistanceUnitForUX: "MILES",
              queryOnlyEnergyStorage: false
            },
            deviceInfo: {
              manufacturer: "ACME Inc.",
              model: "SCOOT-R-US",
              hwVersion: "PVT-2",
              swVersion: "1.0.1"
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('energystorage_sync_3', function() {
    'use strict';

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

    const app = smarthome();

    app.onSync((body, headers) => {
      return {
        requestId: "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
        payload: {
          agentUserId: 1836.15267389,
          devices: [{
            id: "123",
            type: "action.devices.types.CHARGER",
            traits: [
              "action.devices.traits.EnergyStorage"
            ],
            name: {
              defaultNames: [],
              name: "Non-Rechargable Device",
              nicknames: []
            },
            willReportState: true,
            attributes: {
              isRechargeable: false,
              queryOnlyEnergyStorage: true
            },
            deviceInfo: {
              manufacturer: "ACME Inc.",
              model: "THING-NR",
              hwVersion: "PVT-2",
              swVersion: "1.0.1"
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('energystorage_query_1', function() {
    'use strict';

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

    const app = smarthome();

    app.onQuery((body, headers) => {
      return {
        requestId: "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
        payload: {
          devices: {
            123: {
              online: true,
              isPluggedIn: true,
              isCharging: true,
              capacityRemaining: [
                {
                  unit: "SECONDS",
                  rawValue: 36000
                },
                {
                  unit: "PERCENTAGE",
                  rawValue: 90
                }
              ],
              capacityUntilFull: [
                {
                  unit: "SECONDS",
                  rawValue: 120
                }
              ]
            }
          }
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('energystorage_query_2', function() {
    'use strict';

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

    const app = smarthome();

    app.onQuery((body, headers) => {
      return {
        requestId: "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
        payload: {
          devices: {
            123: {
              online: true,
              isPluggedIn: true,
              isCharging: true,
              capacityRemaining: [
                {
                  unit: "MILES",
                  rawValue: 12
                }
              ],
              capacityUntilFull: [
                {
                  unit: "SECONDS",
                  rawValue: 6000
                }
              ]
            }
          }
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('energystorage_query_3', function() {
    'use strict';

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

    const app = smarthome();

    app.onQuery((body, headers) => {
      return {
      requestId: "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
        payload: {
          devices: {
            123: {
              online: true,
              descriptiveCapacityRemaining: "LOW"
            }
          }
        }
      };
    });
    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('energystorage_execute_1', function() {
    const executeRequest =
    {
      "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
      "inputs": [
        {
          "intent": "action.devices.EXECUTE",
          "payload": {
            "commands": [
              {
                "devices": [
                  {
                    "id": "123"
                  }
                ],
                "execution": [
                  {
                    "command": "action.devices.commands.Charge",
                    "params": {
                      "charge": true
                    }
                  }
                ]
              }
            ]
          }
        }
      ]
    }
    ;
    'use strict';

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

    const app = smarthome();

    app.onExecute((body, headers) => {
      return {
        requestId: "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
        payload: {
          commands: [
            {
              ids: [
                "123"
              ],
              status: "SUCCESS",
              states: {
                online: true,
                isPluggedIn: true,
                isCharging: true
              }
            }
          ]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('energystorage_execute_2', function() {
    const executeRequest =
    {
      "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
      "inputs": [
        {
          "intent": "action.devices.EXECUTE",
          "payload": {
            "commands": [
              {
                "devices": [
                  {
                    "id": "123"
                  }
                ],
                "execution": [
                  {
                    "command": "action.devices.commands.Charge",
                    "params": {
                      "charge": false
                    }
                  }
                ]
              }
            ]
          }
        }
      ]
    }
    ;
    'use strict';

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

    const app = smarthome();

    app.onExecute((body, headers) => {
      return {
        requestId: "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
        payload: {
          commands: [
            {
              ids: [
                "123"
              ],
              status: "SUCCESS",
              states: {
                online: true,
                isPluggedIn: true,
                isCharging: false
              }
            }
          ]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  /*
   * action.devices.traits.Timer
   * https://devsite.googleplex.com/actions/smarthome/traits/eap/timer
   */
  it('timer_sync', function() {
    '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.OVEN',
            traits: [
              'action.devices.traits.TemperatureControl',
              'action.devices.traits.StartStop',
              'action.devices.traits.Timer'
            ],
            name: {
              defaultNames: ['AAA Smart Oven'],
              name: 'Oven',
              nicknames: ['conventional oven']
            },
            willReportState: true,
            attributes: {
              temperatureRange: {
                minThresholdCelsius: 65.5,
                maxThresholdCelcius: 288
              },
              temperatureUnitForUX: 'F',
              pausable: false,
              maxTimerLimitSec: 7200,
              commandOnlyTimer: false
            },
            deviceInfo: {
              manufacturer: 'Smart Oven Manufacturers',
              model: 'F600G',
              hwVersion: '3.2',
              swVersion: '11.4'
            },
            customData: {
              fooValue: 74,
              barValue: true,
              bazValue: 'lambtwirl'
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('timer_query_1', function() {
    '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: {
              online: true,
              timerRemainingSec: 60
            },
            status: 'SUCCESS'
          }
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('timer_query_2', function() {
    '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: {
              online: true,
              timerRemainingSec: 60,
              timerPaused: true
            },
            status: 'SUCCESS'
          }
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('timer_query_3', function() {
    '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: {
          errorCode: 'noTimerExists'
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('timer_execute_1', function() {
    const executeRequest =
    {
      "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.TimerStart",
              "params": {
                "timerTimeSec": 300
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {
              timerRemainingSec: 300
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('timer_execute_1_error', function() {
    const executeRequest =
    {
      "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.TimerStart",
              "params": {
                "timerTimeSec": 300
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {
          errorCode: 'valueOutOfRange'
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('timer_execute_2', function() {
    const executeRequest =
    {
      "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.TimerAdjust",
              "params": {
                "timerTimeSec": 60
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {
              /* Added 60s to a timer with 32s remaining */
              timerRemainingSec: 92
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('timer_execute_2_error', function() {
    const executeRequest =
    {
      "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.TimerAdjust",
              "params": {
                "timerTimeSec": 60
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {
          errorCode: 'noTimerExists'
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('timer_execute_3', function() {
    const executeRequest =
    {
      "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.TimerAdjust",
              "params": {
                "timerTimeSec": -30
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {
              /* Removed 30s from a timer with 45s remaining */
              timerRemainingSec: 15
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('timer_execute_3_error', function() {
    const executeRequest =
    {
      "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.TimerAdjust",
              "params": {
                "timerTimeSec": -30
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: {
          errorCode: 'valueOutOfRange'
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('timer_execute_4', function() {
    const executeRequest =
    {
      "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.TimerPause"
            }]
          }]
        }
      }]
    }
    ;
    '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: {
              timerRemainingSec: 240,
              timerPaused: true
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('timer_execute_5', function() {
    const executeRequest =
    {
      "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.TimerResume"
            }]
          }]
        }
      }]
    }
    ;
    '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: {
              timerRemainingSec: 129
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('timer_execute_5_error', function() {
    const executeRequest =
    {
      "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.TimerResume"
            }]
          }]
        }
      }]
    }
    ;
    '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: {
          errorCode: 'noTimerExists'
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('timer_execute_6', function() {
    const executeRequest =
    {
      "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.TimerCancel"
            }]
          }]
        }
      }]
    }
    ;
    '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: {
              timerRemainingSec: 0
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('timer_execute_6_error', function() {
    const executeRequest =
    {
      "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.TimerCancel"
            }]
          }]
        }
      }]
    }
    ;
    '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: {
          errorCode: 'noTimerExists'
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('timer_execute_6_error_2', function() {
    const executeRequest =
    {
      "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.TimerCancel"
            }]
          }]
        }
      }]
    }
    ;
    '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: {
          errorCode: 'unknownError'
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  /*
   * action.devices.traits.TemperatureControl
   * http://developers.google.com/actions/smarthome/traits/temperaturecontrol
   */
  it('temperaturecontrol_sync', function() {
'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.KETTLE',
        traits: [
          'action.devices.traits.OnOff',
          'action.devices.traits.TemperatureControl'
        ],
        name: {
          defaultNames: ['Smart Kettle 1'],
          name: 'Smart Kettle 1',
          nicknames: ['Little teapot']
        },
        willReportState: true,
        attributes: {
          temperatureRange: {
            minThresholdCelsius: 30,
            maxThresholdCelsius: 100
          },
          temperatureStepCelsius: 1,
          temperatureUnitForUX: 'C'
        },
        deviceInfo: {
          manufacturer: 'Smart Home Provider',
          model: 'g1340',
          swVersion: '1.0.31',
          hwVersion: '1.1'
        },
        customData: {
          smartHomeProviderId: 'fiGgZ0vrhFRgwf5XJkna2GRwO8z80J'
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('temperaturecontrol_query', function() {
'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,
          temperatureSetpointCelsius: 177,
          temperatureAmbientCelsius: 150
        },
        status: 'SUCCESS'
      }
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('temperaturecontrol_execute', function() {
    const executeRequest =
{
  "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.SetTemperature",
          "params": {
            "temperature": 176.67
          }
        }]
      }]
    }
  }]
}
    ;
'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: {
          temperatureSetpointCelsius: 177,
          temperatureAmbientCelsius: 140
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  /*
   * action.devices.traits.TemperatureSetting
   * http://developers.google.com/actions/smarthome/traits/temperaturesetting
   */
  it('temperaturesetting_sync', function() {
'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.THERMOSTAT',
        traits: [
          'action.devices.traits.TemperatureSetting'
        ],
        name: {
          defaultNames: ['Smart Thermostat'],
          name: 'Thermostat',
          nicknames: ['Living Room Thermostat']
        },
        willReportState: true,
        attributes: {
          availableThermostatModes: 'off,heat,cool,on',
          thermostatTemperatureUnit: 'F'
        },
        deviceInfo: {
          manufacturer: 'Sirius Cybernetics Corporation',
          model: 't-1000',
          hwVersion: '3.2',
          swVersion: '11.4'
        },
        customData: {
          fooValue: 74,
          barValue: true,
          bazValue: 'lambtwirl'
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('temperaturesetting_query', function() {
'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: {
          online: true,
          thermostatMode: 'cool',
          thermostatTemperatureSetpoint: 23.0,
          thermostatTemperatureAmbient: 25.1,
          thermostatHumidityAmbient: 45.3
        },
        status: 'SUCCESS'
      }
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('temperaturesetting_execute', function() {
    const executeRequest =
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "inputs": [{
    "intent": "action.devices.EXECUTE",
    "payload": {
      "commands": [{
        "devices": [{
          "id": "123",
          "customData": {
            "fooValue": 74,
            "barValue": true,
            "bazValue": "sheepdip"
          }
        }],
        "execution": [{
          "command": "action.devices.commands.ThermostatTemperatureSetpoint",
          "params": {
            "thermostatTemperatureSetpoint": 22.0
          }
        }]
      }]
    }
  }]
}
    ;
'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: {
          thermostatMode: 'cool',
          thermostatTemperatureSetpoint: 22.0,
          thermostatTemperatureAmbient: 25.1,
          thermostatHumidityAmbient: 43.2
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  /*
   * action.devices.traits.Toggles
   * http://developers.google.com/actions/smarthome/traits/toggles
   */
  it('toggles_sync', function() {
'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.DRYER',
        traits: [
          'action.devices.traits.Toggles'
        ],
        name: {
          defaultNames: ['AAA Super Dryer'],
          name: 'Washer',
          nicknames: ['clothes dryer']
        },
        willReportState: true,
        attributes: {
          availableToggles: [{
            name: 'sterilization',
            name_values: [{
              name_synonym: ['bio-clean', 'ultrasound'],
              lang: 'en'
            }]
          }, {
            name: 'energysaving',
            name_values: [{
              name_synonym: ['normal', 'medium', 'high'],
              lang: 'en'
            }]
          }]
        },
        deviceInfo: {
          manufacturer: 'AAA Corporation',
          model: '492134',
          hwVersion: '3.2',
          swVersion: '11.4'
        },
        customData: {
          fooValue: 74,
          barValue: true,
          bazValue: 'lambtwirl'
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('toggles_query', function() {
'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,
          currentToggleSettings: {
            sterilization: true
          }
        },
        456: {
          on: true,
          online: true,
          currentToggleSettings: {
            sterilization: false
          }
        },
        status: 'SUCCESS'
      }
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('toggles_execute', function() {
    const executeRequest =
{
  "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.SetToggles",
          "params": {
            "updateToggleSettings": {
              "sterilization": true
            }
          }
        }]
      }]
    }
  }]
}
    ;
'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: {
           currentToggleSettings: {
             sterilization: true,
             energysaving: false
           }
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
  this.test.app = app;
  this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  /*
   * action.devices.traits.Volume
   * https://devsite.googleplex.com/actions/smarthome/traits/eap/volume
   */
  it('volume_sync', function() {
    '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.SPEAKER',
            traits: [
              'action.devices.traits.OnOff',
              'action.devices.traits.Volume'
            ],
            name: {
              defaultNames: ['Speaker'],
              name: 'Livingroom speaker',
              nicknames: ['Speaker']
            },
            willReportState: true,
            attributes: {
              volumeMaxLevel: 11,
              volumeCanMuteAndUnmute: true,
              volumeDefault: 6,
              levelStepSize: 2,
              commandOnlyVolume: false,
            },
            customData: {
              fooValue: 74,
              barValue: true,
              bazValue: 'foo bar'
            }
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(syncRequest);
  });

  it('volume_query', function() {
    '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,
              currentVolume: 8,
              isMuted: false
            },
            status: 'SUCCESS'
          }
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(queryRequest);
  });

  it('volume_execute_1', function() {
    const executeRequest =
    {
      "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.setVolume",
              "params": {
                "volumeLevel​": 6
              }
            }]
          }]
        }
      }]
    }
    ;
    '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'
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

  it('volume_execute_2', function() {
    const executeRequest =
    {
      "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.volumeRelative",
              "params": {
                "volumeRelativeLevel": -1
              }
            }]
          }]
        }
      }]
    }
    ;
    '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: 'PENDING'
          }]
        }
      };
    });

    // ...

    exports.smarthome = functions.https.onRequest(app);
    this.test.app = app;
    this.test.body = SmartHome.createRequestBody(executeRequest);
  });

});

Java
put("dispenseItems", new HashMap[] {
    new HashMap<String, Object>() {{        put("itemName", "cat food");
        put("amountRemaining", new HashMap<String, Object>() {{            put("amount", 17.0);
            put("units", "CUPS");
        }});
        put("amountLastDispensed", new HashMap<String, Object>() {{            put("amount", 3.0);
            put("unit", "CUPS");
        }});
        put("isCurrentlyDispensing", true);
    }}});
JSON
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "commands": [
      {
        "ids": [
          "123"
        ],
        "status": "SUCCESS",
        "states": {
          "dispenseItems": [
            {
              "itemName": "cat food",
              "amountRemaining": {
                "amount": 17,
                "unit": "CUPS"
              },
              "amountLastDispensed": {
                "amount": 3,
                "unit": "CUPS"
              },
              "isCurrentlyDispensing": true
            }
          ]
        }
      }
    ]
  }
}
UserGive me 3 dog treats.
AssistantSure, dispensing 3 of those from the pet feeder.
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.Dispense",
          "params": {
            "amount": 3.0,
            "unit": "NO_UNITS",
            "item": "dog treats"
          }
        }]
      }]
    }
  }]
}
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: {
          dispenseItems: [{
            itemName: 'dog treats',
            amountRemaining: {
              amount: 27.0,
              unit: 'NO_UNITS'
            },
            amountLastDispensed: {
              amount: 3.0,
              unit: 'NO_UNITS'
            },
            isCurrentlyDispensing: true
          }]
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
Java
put("dispenseItems", new HashMap[] {
    new HashMap<String, Object>() {{        put("itemName", "dog treats");
        put("amountRemaining", new HashMap<String, Object>() {{            put("amount", 27.0);
            put("units", "NO_UNITS");
        }});
        put("amountLastDispensed", new HashMap<String, Object>() {{            put("amount", 3.0);
            put("unit", "NO_UNITS");
        }});
        put("isCurrentlyDispensing", true);
    }}});
JSON
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "commands": [
      {
        "ids": [
          "123"
        ],
        "status": "SUCCESS",
        "states": {
          "dispenseItems": [
            {
              "itemName": "dog treats",
              "amountRemaining": {
                "amount": 27,
                "unit": "NO_UNITS"
              },
              "amountLastDispensed": {
                "amount": 3,
                "unit": "NO_UNITS"
              },
              "isCurrentlyDispensing": true
            }
          ]
        }
      }
    ]
  }
}
UserGive me 1 cup of water.
AssistantSure, dispensing 1 cup of water from the faucet.
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.Dispense",
                "params": {
                  "amount": 1.0,
                  "unit": "CUPS",
                  "item": "water"
                }
              }
            ]
          }
        ]
      }
    }
  ]
}
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: {
          dispenseItems: [{
            itemName: 'water',
            amountLastDispensed: {
              amount: 1.0,
              unit: 'CUPS'
            },
            isCurrentlyDispensing: true
          }]
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
Java
put("dispenseItems", new HashMap[] {
    new HashMap<String, Object>() {{        put("itemName", "water");
        put("amountLastDispensed", new HashMap<String, Object>() {{            put("amount", 1.0);
            put("unit", "CUPS");
        }});
        put("isCurrentlyDispensing", true);
    }}});
JSON
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "commands": [
      {
        "ids": [
          "123"
        ],
        "status": "SUCCESS",
        "states": {
          "dispenseItems": [
            {
              "itemName": "water",
              "amountLastDispensed": {
                "amount": 1,
                "unit": "CUPS"
              },
              "isCurrentlyDispensing": true
            }
          ]
        }
      }
    ]
  }
}
UserFill the cat food bowl.
AssistantSure, filling the cat food bowl.
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.Dispense",
          "params": {
            "presetName": "cat food bowl"
          }
        }]
      }]
    }
  }]
}
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: {
          dispenseItems: [{
            itemName: 'cat food',
            amountLastDispensed: {
              amount: 14.5,
              unit: 'CUPS'
            },  
            isCurrentlyDispensing: true
          }]
        }
      }]
    }
  };
});

// ...

exports.smarthome = functions.https.onRequest(app);
Java
put("dispenseItems", new HashMap[] {
    new HashMap<String, Object>() {{        put("itemName", "dog treats");
        put("amountRemaining", new HashMap<String, Object>() {{            put("amount", 27.0);
            put("units", "NO_UNITS");
        }});
        put("amountLastDispensed", new HashMap<String, Object>() {{            put("amount", 3.0);
            put("unit", "NO_UNITS");
        }});
        put("isCurrentlyDispensing", true);
    }}});
JSON
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "commands": [
      {
        "ids": [
          "123"
        ],
        "status": "SUCCESS",
        "states": {
          "dispenseItems": [
            {
              "itemName": "cat food",
              "amountLastDispensed": {
                "amount": 14.5,
                "unit": "CUPS"
              },
              "isCurrentlyDispensing": true
            }
          ]
        }
      }
    ]
  }
}

Device ERRORS

See the full list of errors and exceptions.

  • dispenseAmountRemainingExceeded: The user tried to dispense an item or amount from a device that does not have enough amount remaining.
  • dispenseAmountAboveLimit: The user tried to dispense an amount that is beyond the limits of what they can ask for in a single query. This is to prevent accidentally dispensing an excessive amount (for example, 500,000 cups of water).
  • dispenseAmountBelowLimit: The user tried to dispense an item or amount from the device the device that is below the minimum amount it can dispense.
  • dispenseFractionalAmountNotSupported: The user tried to dispense a fractional amount of an item that the device cannot split (for example, countable items like dog treats may not be divisible by the device).
  • genericDispenseNotSupported: The user tries to dispense from a device without specifying an item or preset, but the device does not support such functionality (for example, a default dispense action).
  • dispenseUnitNotSupported: The user tries to dispense from a device with a unit not supported for that case (for example, the item is not provided so supported_unit validation was skipped).
  • dispenseFractionalUnitNotSupported: The user tried to dispense a fractional amount of an item which can be split but not for the particular unit specified (for example, a faucet may be able to dispense 2.7 cups but not 2.7 mL).
  • deviceCurrentlyDispensing: The users tries to dispense an item but the device is already dispensing.
  • deviceClogged: The users tries to dispense an item but the device is clogged.
  • deviceBusy: The users tries to dispense an item but the device is busy (generic).

Device EXCEPTIONS

These exceptions can be reported as an exceptionCode in the states object of your response:

  • amountRemainingLow - The user dispenses an item or amount from the device which brings the amount remaining to a low level. You are responsible for defining what constitutes a "low" level.
  • userNeedsToWait - When the user has to wait before the requested item or amount can be successfully dispensed (for example, a faucet will dispense hot water but the user needs to wait for the water to heat up before it begins dispensing).