-
Notifications
You must be signed in to change notification settings - Fork 1
JSON Protocol
Data within stateful is mostly represented as a single 'tiles' JSON object. This page goes into detail on the internal format of this object.
The general structure of the 'tiles' object is Global Metadata followed by one or more Tile objects.
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": []
}A tile object defines one tile entry within stateful. It is split into two parts, payload and buttons:
{
"payload": {},
"buttons": {}
}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": {
"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).
"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"}
]
}
"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"
}
}
"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"
}
},"down": {
"type": 3
},
Button not in use.
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 | ![]() |
|
| 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.
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
}
}
}
]
}


















