Skip to content

Config: GoogleDevices.json

Michael Hallock edited this page Jan 1, 2021 · 12 revisions

The googleDevice.json file provides configuration of the devices that this application manages. This includes:

  1. Metadata about each device, as defined by Google's Devices.
  2. Mapping of Google Traits and their exposed Commands and States to MQTT topics.
  3. Value mappings that allow for dynamic configuration of value and type conversions from and to MQTT to Google Actions values.

Note: Changes to this file will require a restart of the application for those to take effect.

JSON Structure

The JSON file is functionally a dictionary of device ID to device metadata.

{
    "idExample": {
      "id": "idExample",
      "type": "action.devices.types.LIGHT",
      ...
    },
    "idExample2": {
      "id": "idExample2",
      "type": "action.devices.types.LIGHT",
      ...
    },
    ...
}

Metadata

Metadata generally follows the same structure that Google expects to be returned by a SYNC intent, with a few changes.

{
  "id": "zway/diningRoom/diningRoomLight",
  "type": "action.devices.types.LIGHT",
  "willReportState": false,
  "roomHint": "Dining Room",
  "name": {
    "defaultNames": [],
    "name": "dining room light",
    "nicknames": []
  },
  "deviceInfo": {
    "manufacturer": "HomeSeer",
    "model": "WSD100+",
    "hwVersion": "1.0",
    "swVersion": "1.0"
  },
  "traits": [
    {
      "trait": "action.devices.traits.OnOff",
      "attributes": null,
      "commands": { "action.devices.commands.OnOff": { "on": "zway/diningRoom/diningRoomLight/set" } },
      "state": {
        "on": {
          "topic": "zway/diningRoom/diningRoomLight",
          "valueMap": null
      }
    }
  ]
}

Changes include:

  1. "traits" is an array of objects instead of trait names. Details are covered below, but this structure also configures all of the details of MQTT to Google Actions API mappings.
  2. "attributes" moves under "traits", as they are tied to the trait exposed. This lets us distinguish between attributes exposed by one trait or another, instead of them all being jumbled into a single structure.

The rest is a one to one mapping of the Google Actions API SYNC contract. ID is an internal identifier, but its recommended to use some base MQTT topic here.

Traits

A device specifies what "traits" it exposes, as per the Google Traits specification. These traits in turn specify what Commands the device supports, and what State it exposes, and Attributes that are specific to the trait (specifically currently used for Modes, Toggles, and CameraStreams).

Note: Just because a trait says it exposes a command or a state, does not mean you have to expose it here. It just means that QUERY and EXECUTE intents for these will be ignored.

Attributes

Attributes share the same schema as the Google Actions API contract. They are just split up per trait. Please see the trait documentation for what you might need to put here. It is NULL by default for most traits, as it isn't needed.

Commands

Commands is a mapping of command name to the command parameters that it supports, and the MQTT topic that it translates to.

"commands": { "action.devices.commands.OnOff": { "on": "zway/diningRoom/diningRoomLight/set" } }

In the above example, the command "action.devices.commands.OnOff" supports a parameter, "on". When an EXECUTE intent arrives with this command and parameter, it will look up the correct MQTT topic assigned here, and pass the value through as an MQTT message to that topic. Note that complex params, such as "currentModeSettings" of the modes trait, the structure is flattened and "." delimited:

"commands": { "action.devices.commands.SetModes": { "updateModeSettings.input source": "someTopic/set" } }

Commands Delegation

Command handling can be delegated to an external handler. Any incoming command will be to a standard formatted MQTT topic structured as google/home/execution/DEVICEID/COMMAND. Any command params will be passed as the message payload as a serialized JSON string for external processing. If no parameters are passed by Google, the payload will be empty. No value mapping or other manipulations will occur, the command parameters will be sent verbatim as they arrive from Google.

A SUCCESS response will be immediately returned to Google in this case.

Older implementations would have allowed this to be sent to arbitrary topics by configuration a command as below. These should be removed in favor of the automatically published command topics, as it presents a more generic approach. In the future, the validation systems will provide an option to do ONLY command delegation if desired.

    "commands": { "action.devices.commands.mediaNext": { "_": "some/command/topic" } }

State

States provide the mappings from Google Actions API state values and MQTT topics/values. The keys of the mapping are the State parameters as defined in Google's Trait documents, and much like Commands, complex state parameters are flattened and "." delimited.

Values are a an object with the following format:

"state": {
  "currentModeSettings.input source": {
    "topic": "harmony/default/activity",
    "valueMap": [
      { "mqtt": "Watch TV", "type": "value", "google": "tv" },
      { "mqtt": "Watch Shield TV", "type": "value", "google": "media player" },
      { "mqtt": "Play PS4", "type": "value", "google": "game console" },
      { "mqtt": "PowerOff", "type": "value", "google": "off" }
    ]
  }
}

In this case, the state parameter "currentModeSettings.input source" is mapped to get its value from the MQTT topic "harmony/default/activity". It specifies that Google will expect this value to be a "string". And it provides "Value Maps" (See below) that translate values that MQTT might have to values that are valid for Google.

Value Maps

Value maps allow for translation of values from MQTT to Google, as well as from Google back to MQTT payloads for Commands. There are a few types of these in the application that fit my needs, but hopefully are generic enough to be helpful to others. If these don't meet your needs, you'll need to put some intermediary between the values published by this app and your actual MQTT topics to translate. Without any of these in place, it is assumed the MQTT values will match Google's expectations.

When evaluated for translating incoming Commands, or internal State values to fulfill a QUERY intent, these will be evaluated in the order they are defined, and the first match wins. In all cases, the MQTT value is expected

Types include:

  1. Value - Bidirectional, exact match, one-to-one mapping the value on one side will be translated to the value on the other.

  2. Range - Unidirectional numeric conversion of MQTT value to a static Google value. If the Google side matches during a command, it will pass through the original Google value as is, therefore combining with a prior Value based map with the same Google value may be necessary to ensure that it translates to a specific numeric value like below. This rule would ensure that a light that supports both "OnOff" and "Brightness" translates the Google "on" parameter to the payload "on" in an EXECUTE, but on a QUERY will fall through to the "range" value map, and map any value between 1 and 100 to "on: true" in the Google response:

    { "type": "value", "mqtt": "on", "google": "true" },
    { "type": "range", "mqttMin": 1.0, "mqttMax": 100.0, "google": "true" }
    
  3. Static - Specifically for the special snowflake "CameraStream" intent, which maps things differently. Whenever Google sends an EXECUTE with a parameter marked with this, it will skip sending any MQTT message, but the EXECUTE result will return the specific static value specified. Note the missing "topic" for the state definition below:

    "state": {
      "cameraStreamAccessUrl": {
        "topic": null,
        "googleType": "string",
        "valueMap": [
            { "type": "static", "google": "http://someUrlToACameraStream" }
        ]
      },
      ...
    }
    
  4. Celsius - Used for places where a given MQTT value is in Fahrenheit and must be converted to Celsius for Google, and back to Fahrenheit on the incoming command. Note you only need this if your MQTT measurements are NOT in Celsius already. Google requires Celsius as a standard on its reported temperatures.

    "valueMap": [
      { "type": "celsius" }
    ]
    
  5. RegEx - Allows for RegEx based transformation in both directions. Uses the googleSearch regex to match the google incoming value, and replace it with the mqttReplace regex string. Uses the 'mqttSearch' regex to match the MQTT incoming value, and replace it with the googleReplace regex string. Use for more complicated parsing situations.

    "valueMap": [
      {
        "type": "regex",
        "googleSearch": "^googleValueToReplace$",
        "googleReplace": "RegExReplaceStringToConvertMqttValueTo",
        "mqttSearch": "^mqttValueToReplace$",
        "mqttReplace": "RegExReplaceStringToConvertGoogleValueTo",
      }
    ]
    
  6. LinearRange - Allows bi-directional mapping of two ranges automatically calculating equivalents.

    "valueMap": [
      {
        "type": "linearRange",
        "googleMin": 0,
        "googleMax": 100,
        "mqttMin": 0,
        "mqttMax": 254,
      }
    ]