Skip to content

JSON Protocol

kennedn edited this page Jul 4, 2022 · 3 revisions

Data within stateful is mostly represented as a single 'tiles' JSON object. This page goes into detail on the internal format of this object.

JSON Structure

The general structure of the 'tiles' object is Global Metadata followed by one or more Tile objects.

Global Metadata

Global Settings are top level keys that affect every tile or the system in general.

{
  "default_idx": 0, 
  "open_default": false,
  "debug_logging": false,
  "tile_globals": false,
  "base_url": "",
  "headers": {},
  "tiles": []
}
Key Expected type Description
default_idx number Configures which menu item is initially selected when the app is started
open_default boolean Automatically enters the selected menu item when the app starts
debug_logging boolean Turn debug logging on or off in configuration menu (see Debug Logging)
tile_globals boolean Change whether Base URL and Global Headers are set globally or per tile in configuration menu (see Per Tile Globals)
base_url string Prepended to all tile defined URLs
headers Object Combined with any tile defined headers
tiles Objects[] An array of tile objects, see Tiles

Example:

{
  "default_idx": 0, 
  "open_default": true,
  "debug_logging": false,
  "tile_globals": false,
  "base_url": "https://cool.api/api/v1.0/",
  "headers": {
    "Content-Type": "application/json",
    "Authorization": "Basic Tm9zZXkgb25lIGFyZW50IHlvdSA6KQ=="
  },
  "tiles": []
}

Tiles

A tile object defines one tile entry within stateful. It is split into two parts, payload and buttons:

{
  "payload": {},
  "buttons": {}
}

Payload

The payload object contains all of the information required to build up a tile watch-side. Values are packed and sent down to the watch app:

{
  "color": "",
  "highlight": "",
  "texts": [],
  "icon_keys": []
}
Key Expected type Description
color hex-string A 6 digit hex string, defines the main color for the tile / menu item
highlight boolean A 6 digit hex string, defines the highlight color for the tile / menu item
texts string[] An array of 7 strings representing 6 button clicks and 1 menu title:
up, up_hold, mid, mid_hold, down, down_hold, title
icon_keys string[] An array of 7 strings representing 6 icon_keys for each button and 1 menu icon_key:
up, up_hold, mid, mid_hold, down, down_hold, title
See Icon Keys

Note: texts & icon_keys must always have 7 values, any buttons that are disabled should specify an empty string, as shown in the below example.

Example:

{
  "color": "#0055aa",
  "highlight": "#00aaff",
  "texts": [
    "office",
    "attic",
    "bedroom",
    "hall down",
    "hall up",
    "",
    "lights"
  ],
  "icon_keys": [
    "eccbc87e",
    "eccbc87e",
    "eccbc87e",
    "eccbc87e",
    "eccbc87e",
    "",
    "eccbc87e"
  ]
}

Buttons

"buttons": {
  "up": {},
  "up_hold": {},
  "mid": {},
  "mid_hold": {},
  "down": {},
  "down_hold": {}
}

The buttons object consists of 6 buttons. Each of these specifies the values required to call a REST endpoint for a specific click.

up, mid and down are accessible immediately after entering a given tile, up_hold, mid_hold and down_hold are 'swapped in' when mid is long-pressed, this can be done any number of times to toggle between the two sets.

There are four types of button:

Button Type Value Description
Local 0 Send a simple XHR request and optionally maintain a local tracker
Stateful 1 Send an XHR request and derive a status afterwards from an additional XHR request
Status Only 2 Directly derive a status from an initial XHR request
Disabled 3 Disables the buttons functionality

Note: Six button objects should exist for each tile, if a button is not to be used, the type should be specified as 3 (Disabled).

Local Type

"up": {
  "type": 0,
  "method": "",
  "url": "",
  "headers": {},
  "data": [],
},

Local buttons are specifically for endpoints that cannot provide a status or where it does not make sense to request a status. Some examples may be turning the volume up on a TV or triggering an infrared bulb that cannot describe what state it is in.

Key Expected type Description
type number Button Type
method string XHR Method
url string Partial or full URL, see base_url in global settings
headers Object Optional headers to send alongside data, combined with headers in global settings
data Objects[] or Object One or more data object to send to the endpoint


The buttons behavior will change based on the number of elements provided in the data key:

Number Side Effects
1 None, simply calls an XHR request
2 Each JSON object will be used in a round robin fashion
when index 0 fires, a green background will display on watch,
when index 1 fires, a red background will display on watch
3+ Each JSON object will be used in a round robin fashion

Examples:

1 data item:

"up": {
  "type": 0,
  "method": "PUT",
  "url": "tvcom/ir_key",
  "headers": {},
  "data": {"code": "vol_up"}
}

2 data items:

"up_hold": {
  "type": 0,
  "method": "PUT",
  "url": "bulb",
  "headers": {},
  "data": [
    {"code": "on"},
    {"code": "off"}
  ]
}

3 data items:

"mid": {
  "type": 0,
  "method": "PUT",
  "url": "tvcom/input_select",
  "headers": {},
  "data": [
    {"code": "hdmi_1"},
    {"code": "hdmi_2"},
    {"code": "hdmi_3"}
  ]
}

Stateful Type

"down": {
  "type": 1,
  "method": "",
  "url": "",
  "headers": {},
  "data": [],
  "status": {
    "method": "",
    "url": "",
    "headers": {},
    "data": {},
    "variable": "",
    "good": ,
    "bad": 
  }
},

Stateful buttons are great for changing the state of something (e.g toggle a light bulb) and then understanding the status of that endpoint after you changed its state. Some examples are a WiFi bulb or a televisions power state.

The buttons behavior will change based on the number of elements provided in the data key:

Number Side Effects
1 None
2 Each JSON object will be used in a round robin fashion
Key Expected type Description
type number Button Type
method string XHR Method
url string Partial or full URL, see base_url in global settings
headers Object Optional headers to send alongside data, combined with headers in global settings
data Objects[] or Object One or more data object to send to the endpoint
status.method string XHR status method
status.url string Partial or full status URL, see base_url in global settings
status.headers Object Optional headers to send alongside data, combined with headers in global settings
status.data Object A single object to send to the endpoint
status.variable string A variable to extract from the return data, use dot and/or array notation to descend into a nested object
status.good var If this matches the extracted status.variable, display green background on watch
status.bad var If this matches the extracted status.variable, display red background on watch

Examples: 1 data item:

"mid": {
  "type": 1,
  "method": "PUT",
  "url": "wifi_bulb/bedroom",
  "headers": {},
  "data": {"code": "toggle"},
  "status": {
    "method": "PUT",
    "url": "wifi_bulb/bedroom",
    "headers": {},
    "data": {"code": "status"},
    "variable": "onoff",
    "good": 1,
    "bad": 0
  }
}

2 data items:

"mid_hold": {
  "type": 1,
  "method": "PUT",
  "url": "tvcom/power",
  "headers": {},
  "data": [
    {"code": "on"},
    {"code": "off"}
  ],
  "status": {
    "method": "PUT",
    "url": "tvcom/power",
    "headers": {},
    "data": {"code": "status"},
    "variable": "status.power[0].onoff",
    "good": "on",
    "bad": "off"
  }
}

Status-Only Type

"mid": {
  "type": 2,
  "status": {
    "method": "",
    "url": "",
    "headers": {},
    "data": {},
    "variable": "",
    "good": ,
    "bad": 
  }
},

Status only buttons are similar to stateful buttons, but they are intended for situations where you do not want to change an endpoints state but simply want to understand what state that endpoint is in. An Example may be if a computer is on or off.

Key Expected type Description
type number Button Type
status.method string XHR status method
status.url string Partial or full status URL, see base_url in global settings
status.headers Object Optional headers to send alongside data, combined with headers in global settings
status.data Object A single object to send to the endpoint
status.variable string A variable to extract from the return data, use dot and/or array notation to descend into a nested object
status.good var If this matches the extracted status.variable, display green background on watch
status.bad var If this matches the extracted status.variable, display red background on watch

Example:

"mid": {
  "type": 2,
  "status": {
    "method": "PUT",
    "url": "tvcom/power",
    "headers": {},
    "data": {"code": "status"},
    "variable": "status.power[0].onoff",
    "good": "on",
    "bad": "off"
  }
},

Disabled Type

"down": {
  "type": 3
},

Button not in use.

Icon Keys

The icon key system defines a standard set of icons which are compiled alongside the application.

Internally, icons are tracked via an icon_key. An icon_key is a SHA1 hash of either the ResourceID (in the case of a compiled icon) or the URL (in the case of a custom icon). The resultant icon_key is the first 8 characters of this SHA1 hash.

The standard set of icons are defined as follows:

Key Label Icon
c4ca4238 Default
c81e728d Tv
eccbc87e Bulb
a87ff679 Monitor
e4da3b7f Call
1679091c Plus
8f14e45f Minus
c9f0f895 Star
45c48cce Power
d3d94468 Input
6512bd43 Mute
c20ad4d7 Aspect
c51ce410 Plant
aab32389 Mail
9bf31c7f Bolt
c74d97b0 Notification
70efdf2e Flame
6f4922f4 Unlock
1f0e3dad Lock
98f13708 Droplet

icon_keys can be configured for each tile in their respective Payload section.

Example JSON

Fully constructed JSON objects can be pasted directly into the clay config 'JSON Manager' section. Example:

{
  "default_idx": 0,
  "open_default": true,
  "debug_logging": false,
  "tile_globals": false,
  "base_url": "https://cool.api/api/v1.0/",
  "headers": {
    "Content-Type": "application/json",
    "Authorization": "Basic Tm9zZXkgb25lIGFyZW50IHlvdSA6KQ=="
  },
  "tiles": [{
      "payload": {
        "color": "#1c7d7a",
        "highlight": "#1c817e",
        "texts": [
          "office",
          "attic",
          "bedroom",
          "",
          "hall",
          "",
          "upstairs"
        ],
        "icon_keys": [
          "eccbc87e",
          "eccbc87e",
          "eccbc87e",
          "",
          "eccbc87e",
          "",
          "eccbc87e"
        ]
      },
      "buttons": {
        "up": {
          "type": "1",
          "method": "PUT",
          "url": "meross/office",
          "headers": {},
          "data": {
            "code": "toggle"
          },
          "status": {
            "method": "PUT",
            "url": "meross/office",
            "headers": {},
            "data": {
              "code": "status"
            },
            "variable": "onoff",
            "good": 1,
            "bad": 0
          }
        },
        "up_hold": {
          "type": 1,
          "method": "PUT",
          "url": "meross/attic",
          "headers": {},
          "data": {
            "code": "toggle"
          },
          "status": {
            "method": "PUT",
            "url": "meross/attic",
            "headers": {},
            "data": {
              "code": "status"
            },
            "variable": "onoff",
            "good": 1,
            "bad": 0
          }
        },
        "mid": {
          "type": 1,
          "method": "PUT",
          "url": "meross/bedroom",
          "headers": {},
          "data": {
            "code": "toggle"
          },
          "status": {
            "method": "PUT",
            "url": "meross/bedroom",
            "headers": {},
            "data": {
              "code": "status"
            },
            "variable": "onoff",
            "good": 1,
            "bad": 0
          }
        },
        "mid_hold": {
          "type": 3
        },
        "down": {
          "type": 1,
          "method": "PUT",
          "url": "meross/hall_up",
          "headers": {},
          "data": {
            "code": "toggle"
          },
          "status": {
            "method": "PUT",
            "url": "meross/hall_up",
            "headers": {},
            "data": {
              "code": "status"
            },
            "variable": "onoff",
            "good": 1,
            "bad": 0
          }
        },
        "down_hold": {
          "type": 3
        }
      }
    },
    {
      "payload": {
        "color": "#52037c",
        "highlight": "#6e04a9",
        "texts": [
          "bulb",
          "",
          "lamp",
          "",
          "hall",
          "",
          "downstairs"
        ],
        "icon_keys": [
          "eccbc87e",
          "",
          "eccbc87e",
          "",
          "eccbc87e",
          "",
          "eccbc87e"
        ]
      },
      "buttons": {
        "up": {
          "type": 1,
          "method": "PUT",
          "url": "meross/livingroom",
          "headers": {},
          "data": {
            "code": "toggle"
          },
          "status": {
            "method": "PUT",
            "url": "meross/livingroom",
            "headers": {},
            "data": {
              "code": "status"
            },
            "variable": "onoff",
            "good": 1,
            "bad": 0
          }
        },
        "up_hold": {
          "type": 3
        },
        "mid": {
          "type": 1,
          "method": "PUT",
          "url": "meross/livingroom_lamp",
          "headers": {},
          "data": {
            "code": "toggle"
          },
          "status": {
            "method": "PUT",
            "url": "meross/livingroom_lamp",
            "headers": {},
            "data": {
              "code": "status"
            },
            "variable": "onoff",
            "good": 1,
            "bad": 0
          }
        },
        "mid_hold": {
          "type": 3
        },
        "down": {
          "type": 1,
          "method": "PUT",
          "url": "meross/hall_down",
          "headers": {},
          "data": {
            "code": "toggle"
          },
          "status": {
            "method": "PUT",
            "url": "meross/hall_down",
            "headers": {},
            "data": {
              "code": "status"
            },
            "variable": "onoff",
            "good": 1,
            "bad": 0
          }
        },
        "down_hold": {
          "type": 3
        }
      }
    },
    {
      "payload": {
        "color": "#000000",
        "highlight": "#FFFFFF",
        "texts": [
          "power",
          "vol up",
          "input",
          "mute",
          "aspect",
          "vol down",
          "tv"
        ],
        "icon_keys": [
          "45c48cce",
          "1679091c",
          "d3d94468",
          "6512bd43",
          "c20ad4d7",
          "8f14e45f",
          "c81e728d"
        ]
      },
      "buttons": {
        "up": {
          "type": 1,
          "method": "PUT",
          "url": "tvcom/ir_key",
          "headers": {},
          "data": {
            "code": "power"
          },
          "status": {
            "method": "PUT",
            "url": "tvcom/power",
            "headers": {},
            "data": {
              "code": "status"
            },
            "variable": "status",
            "good": "on",
            "bad": "off"
          }
        },
        "up_hold": {
          "type": 0,
          "method": "PUT",
          "url": "tvcom/volume",
          "headers": {},
          "variable": "code",
          "data": {
            "code": "+5"
          }
        },
        "mid": {
          "type": 0,
          "method": "PUT",
          "url": "tvcom/ir_key",
          "headers": {},
          "data": {
            "code": "input"
          }
        },
        "mid_hold": {
          "type": 0,
          "method": "PUT",
          "url": "tvcom/ir_key",
          "headers": {},
          "data": {
            "code": "mute"
          }
        },
        "down": {
          "type": 0,
          "method": "PUT",
          "url": "tvcom/ir_key",
          "headers": {},
          "data": {
            "code": "ratio"
          }
        },
        "down_hold": {
          "type": 0,
          "method": "PUT",
          "url": "tvcom/volume",
          "headers": {},
          "variable": "code",
          "data": {
            "code": "-5"
          }
        }
      }
    },
    {
      "payload": {
        "color": "#FF5500",
        "highlight": "#FFAA00",
        "texts": [
          "pc status",
          "pc",
          "laptop status",
          "laptop",
          "phone finder",
          "",
          "devices"
        ],
        "icon_keys": [
          "a87ff679",
          "45c48cce",
          "a87ff679",
          "45c48cce",
          "e4da3b7f",
          "",
          "a87ff679"
        ]
      },
      "buttons": {
        "up": {
          "type": 2,
          "status": {
            "method": "PUT",
            "url": "pc",
            "headers": {},
            "data": {
              "code": "status"
            },
            "variable": "status",
            "good": "on",
            "bad": "off"
          }
        },
        "up_hold": {
          "type": 0,
          "method": "PUT",
          "url": "pc",
          "headers": {},
          "data": {
            "code": "power"
          }
        },
        "mid": {
          "type": 2,
          "status": {
            "method": "PUT",
            "url": "laptop",
            "headers": {},
            "data": {
              "code": "status"
            },
            "variable": "status",
            "good": "on",
            "bad": "off"
          }
        },
        "mid_hold": {
          "type": 0,
          "method": "PUT",
          "url": "laptop",
          "headers": {},
          "data": {
            "code": "power"
          }
        },
        "down": {
          "type": 0,
          "method": "PUT",
          "url": "alert",
          "headers": {},
          "data": {
            "message": "find_phone"
          }
        },
        "down_hold": {
          "type": 3
        }
      }
    }
  ]
}

Clone this wiki locally