Files
GarminHomeAssistant/config.schema.json
Philip Abbey 3404c7f679 Update schema for numeric tap_action and HISTORY
Add schema metadata and stricter validation for numeric tap_action: include title & description, disallow additionalProperties on the tap_action and its picker properties to better define the number picker payload. Update HISTORY.md with a 3.14 entry documenting numeric items now supporting tap_action.data and the PIN/menu behavior change, and credit the contributor.
2026-06-24 01:12:20 +01:00

1074 lines
32 KiB
JSON

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"$schema": {
"type": "string",
"description": "The schema will prevent JSON file errors."
},
"title": {
"type": "string",
"description": "Top level menu title"
},
"glance": {
"$ref": "#/$defs/glance"
},
"items": {
"$ref": "#/$defs/items"
}
},
"required": [
"items"
],
"additionalProperties": false,
"$defs": {
"toggle": {
"type": "object",
"properties": {
"entity": {
"$ref": "#/$defs/entity"
},
"name": {
"$ref": "#/$defs/name"
},
"type": {
"$ref": "#/$defs/type",
"const": "toggle"
},
"content": {
"$ref": "#/$defs/content"
},
"tap_action": {
"$ref": "#/$defs/tap_action",
"additionalProperties": false
},
"enabled": {
"$ref": "#/$defs/enabled"
},
"exit": {
"$ref": "#/$defs/exit",
"deprecated": true
}
},
"required": [
"entity",
"name",
"type"
],
"additionalProperties": false
},
"template": {
"deprecated": true,
"oneOf": [
{
"type": "object",
"properties": {
"entity": {
"$ref": "#/$defs/entity",
"deprecated": true,
"title": "Schema change:",
"description": "Use 'tap_action' instead to mirror Home Assistant."
},
"name": {
"$ref": "#/$defs/name"
},
"content": {
"$ref": "#/$defs/content"
},
"type": {
"$ref": "#/$defs/type",
"const": "template",
"deprecated": true,
"title": "Schema change:",
"description": "Use 'info' or 'tap' instead."
},
"enabled": {
"$ref": "#/$defs/enabled"
}
},
"required": [
"name",
"content",
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"entity": {
"$ref": "#/$defs/entity"
},
"name": {
"$ref": "#/$defs/name"
},
"content": {
"$ref": "#/$defs/content"
},
"type": {
"$ref": "#/$defs/type",
"const": "template",
"deprecated": true,
"title": "Schema change:",
"description": "Use 'info' or 'tap' instead."
},
"tap_action": {
"$ref": "#/$defs/tap_action_tap"
},
"enabled": {
"$ref": "#/$defs/enabled"
},
"exit": {
"$ref": "#/$defs/exit",
"deprecated": true
}
},
"required": [
"name",
"content",
"type",
"tap_action"
],
"additionalProperties": false
}
]
},
"info": {
"type": "object",
"properties": {
"name": {
"$ref": "#/$defs/name"
},
"content": {
"$ref": "#/$defs/content"
},
"type": {
"$ref": "#/$defs/type",
"const": "info"
},
"enabled": {
"$ref": "#/$defs/enabled"
}
},
"required": [
"name",
"content",
"type"
],
"additionalProperties": false
},
"tap": {
"type": "object",
"properties": {
"entity": {
"$ref": "#/$defs/entity"
},
"name": {
"$ref": "#/$defs/name"
},
"type": {
"$ref": "#/$defs/type",
"const": "tap"
},
"content": {
"$ref": "#/$defs/content"
},
"service": {
"$ref": "#/$defs/action",
"deprecated": true,
"title": "Schema change:",
"description": "Use 'tap_action' instead to mirror Home Assistant."
},
"tap_action": {
"$ref": "#/$defs/tap_action_tap"
},
"enabled": {
"$ref": "#/$defs/enabled"
},
"exit": {
"$ref": "#/$defs/exit",
"deprecated": true
}
},
"required": [
"name",
"type"
],
"additionalProperties": false
},
"group": {
"type": "object",
"properties": {
"entity": {
"$ref": "#/$defs/entity",
"type": "string",
"deprecated": true,
"title": "Schema change:",
"description": "'entity' is no longer necessary and should now be removed."
},
"name": {
"title": "Menu item's familiar name.",
"type": "string"
},
"title": {
"title": "Sub menu's title once displayed.",
"type": "string"
},
"type": {
"$ref": "#/$defs/type",
"const": "group"
},
"content": {
"$ref": "#/$defs/content"
},
"items": {
"$ref": "#/$defs/items"
},
"enabled": {
"$ref": "#/$defs/enabled"
}
},
"required": [
"name",
"type",
"items"
],
"additionalProperties": false
},
"numeric": {
"type": "object",
"allOf": [
{
"properties": {
"name": {
"$ref": "#/$defs/name"
},
"type": {
"$ref": "#/$defs/type",
"const": "numeric"
},
"content": {
"$ref": "#/$defs/content"
},
"tap_action": {
"title": "Tap Action",
"description": "Numeric tap action definition to include the number picker.",
"properties": {
"action": {
"$ref": "#/$defs/action"
},
"data": {
"type": "object",
"title": "Additional action data",
"description": "Fixed Home Assistant service data. The selected picker value is merged into this object using the picker's data_attribute. Service-specific fields cannot be schema checked here."
},
"picker": {
"type": "object",
"title": "Number picker configuration",
"description": "'attribute' field is optional.",
"properties": {
"min": {
"type": "number",
"title": "Minimum Value"
},
"max": {
"type": "number",
"title": "Maximum Value"
},
"step": {
"type": "number",
"title": "Step Size"
},
"attribute": {
"type": "string",
"title": "Attribute on the entity",
"description": "Attribute on the entity with the current numeric value. To use the state of the entity, do not specify."
},
"data_attribute": {
"type": "string",
"title": "Attribute on the action data",
"description": "Attribute on the action data for the value to set."
}
},
"required": [
"min",
"max",
"step",
"data_attribute"
],
"additionalProperties": false
}
},
"required": [
"action",
"picker"
],
"additionalProperties": false
},
"enabled": {
"$ref": "#/$defs/enabled"
},
"exit": {
"$ref": "#/$defs/exit"
},
"entity": {
"$ref": "#/$defs/entity"
}
},
"required": [
"name",
"type",
"entity",
"tap_action"
],
"additionalProperties": false
},
{
"properties": {
"entity": {
"pattern": "^(light|input_number|number|fan|valve|cover|media_player|climate)\\.[^.]+$"
}
},
"if": {
"properties": {
"entity": {
"pattern": "^light\\.[^.]+$"
}
}
},
"then": {
"properties": {
"tap_action": {
"properties": {
"action": {
"const": "light.turn_on"
},
"picker": {
"properties": {
"attribute": {
"const": "brightness"
},
"data_attribute": {
"const": "brightness"
},
"min": {
"type": "integer",
"minimum": 0
},
"max": {
"type": "integer",
"max": 255,
"description": "Lights are not a percentage."
}
}
}
}
}
}
},
"else": {
"if": {
"properties": {
"entity": {
"pattern": "^input_number\\.[^.]+$"
}
}
},
"then": {
"properties": {
"tap_action": {
"properties": {
"action": {
"const": "input_number.set_value"
},
"picker": {
"properties": {
"data_attribute": {
"const": "value"
}
},
"not": {
"required": [
"attribute"
]
}
}
}
}
}
},
"else": {
"if": {
"properties": {
"entity": {
"pattern": "^number\\.[^.]+$"
}
}
},
"then": {
"properties": {
"tap_action": {
"properties": {
"action": {
"const": "number.set_value"
},
"picker": {
"properties": {
"data_attribute": {
"const": "value"
}
},
"not": {
"required": [
"attribute"
]
}
}
}
}
}
},
"else": {
"if": {
"properties": {
"entity": {
"pattern": "^fan\\.[^.]+$"
}
}
},
"then": {
"properties": {
"tap_action": {
"properties": {
"action": {
"const": "fan.set_percentage"
},
"picker": {
"properties": {
"attribute": {
"const": "percentage"
},
"data_attribute": {
"const": "percentage"
},
"min": {
"type": "integer",
"minimum": 0
},
"max": {
"type": "integer",
"maximum": 100
}
}
}
}
}
}
},
"else": {
"if": {
"properties": {
"entity": {
"pattern": "^valve\\.[^.]+$"
}
}
},
"then": {
"properties": {
"tap_action": {
"properties": {
"action": {
"const": "valve.set_valve_position"
},
"picker": {
"properties": {
"attribute": {
"const": "position"
},
"data_attribute": {
"const": "position"
},
"min": {
"type": "integer",
"minimum": 0
},
"max": {
"type": "integer",
"maximum": 100
}
}
}
}
}
}
},
"else": {
"if": {
"properties": {
"entity": {
"pattern": "^cover\\.[^.]+$"
}
}
},
"then": {
"allOf": [
{
"properties": {
"tap_action": {
"properties": {
"action": {
"enum": [
"cover.set_position",
"cover.set_tilt_position"
]
}
}
}
}
},
{
"if": {
"properties": {
"tap_action": {
"properties": {
"action": {
"const": "cover.set_tilt_position"
}
}
}
}
},
"then": {
"properties": {
"tap_action": {
"properties": {
"action": {
"const": "cover.set_tilt_position"
},
"picker": {
"properties": {
"attribute": {
"const": "tilt_position"
},
"data_attribute": {
"const": "tilt_position"
},
"min": {
"type": "integer",
"minimum": 0
},
"max": {
"type": "integer",
"maximum": 100
}
}
}
}
}
}
},
"else": {
"properties": {
"tap_action": {
"properties": {
"action": {
"const": "cover.set_position"
},
"picker": {
"properties": {
"attribute": {
"const": "position"
},
"data_attribute": {
"const": "position"
},
"min": {
"type": "integer",
"minimum": 0
},
"max": {
"type": "integer",
"maximum": 100
}
}
}
}
}
}
}
}
]
},
"else": {
"if": {
"properties": {
"entity": {
"pattern": "^media_player\\.[^.]+$"
}
}
},
"then": {
"properties": {
"tap_action": {
"properties": {
"action": {
"const": "media_player.volume_set"
},
"picker": {
"properties": {
"attribute": {
"const": "volume_level"
},
"data_attribute": {
"const": "volume_level"
},
"min": {
"type": "number",
"minimum": 0
},
"max": {
"type": "number",
"maximum": 1,
"description": "Fraction [0,1], not percentage."
}
}
}
}
}
}
},
"else": {
"if": {
"properties": {
"entity": {
"pattern": "^climate\\.[^.]+$"
}
}
},
"then": {
"tap_action": {
"properties": {
"properties": {
"action": {
"const": "climate.set_temperature"
},
"picker": {
"properties": {
"attribute": {
"const": "temperature"
},
"data_attribute": {
"const": "temperature"
}
},
"not": {
"required": [
"attribute"
]
}
}
}
}
}
}
}
}
}
}
}
}
}
}
]
},
"type": {
"title": "Menu item type",
"description": "One of 'info', 'tap', 'toggle', 'group' or 'numeric'."
},
"items": {
"type": "array",
"items": {
"examples": [
{
"type": "tap",
"name": "Example",
"tap_action": {
"action": "notify.notify",
"data": {
"message": "Example"
}
}
},
{
"type": "toggle",
"name": "Example",
"entity": "switch.example"
},
{
"type": "group",
"name": "Example",
"title": "Example",
"items": []
},
{
"type": "numeric",
"name": "Example",
"entity": "light.example",
"tap_action": {
"action": "light.turn_on",
"picker": {
"attribute": "brightness",
"data_attribute": "brightness",
"min": 0,
"max": 255,
"step": 1
}
}
},
{
"type": "numeric",
"name": "Example",
"entity": "input_number.example",
"tap_action": {
"action": "input_number.set_value",
"picker": {
"data_attribute": "value",
"min": 0,
"max": 100,
"step": 1
}
}
},
{
"type": "numeric",
"name": "Example",
"entity": "number.example",
"tap_action": {
"action": "number.set_value",
"picker": {
"data_attribute": "value",
"min": 0,
"max": 100,
"step": 1
}
}
},
{
"type": "numeric",
"name": "Example",
"entity": "fan.example",
"tap_action": {
"action": "fan.set_percentage",
"picker": {
"attribute": "percentage",
"data_attribute": "percentage",
"min": 0,
"max": 100,
"step": 1
}
}
},
{
"type": "numeric",
"name": "Example",
"entity": "valve.example",
"tap_action": {
"action": "valve.set_valve_position",
"picker": {
"attribute": "position",
"data_attribute": "position",
"min": 0,
"max": 100,
"step": 1
}
}
},
{
"type": "numeric",
"name": "Example",
"entity": "cover.example",
"tap_action": {
"action": "cover.set_position",
"picker": {
"attribute": "position",
"data_attribute": "position",
"min": 0,
"max": 100,
"step": 1
}
}
},
{
"type": "numeric",
"name": "Example",
"entity": "cover.example",
"tap_action": {
"action": "cover.set_tilt_position",
"picker": {
"attribute": "tilt_position",
"data_attribute": "tilt_position",
"min": 0,
"max": 100,
"step": 1
}
}
},
{
"type": "numeric",
"name": "Example",
"entity": "media_player.example",
"tap_action": {
"action": "media_player.volume_set",
"picker": {
"attribute": "volume_level",
"data_attribute": "volume_level",
"min": 0,
"max": 1,
"step": 0.01
}
}
},
{
"type": "numeric",
"name": "Example",
"entity": "climate.example",
"tap_action": {
"action": "climate.set_temperature",
"picker": {
"attribute": "temperature",
"data_attribute": "temperature"
}
}
}
],
"allOf": [
{
"properties": {
"type": {
"enum": [
"toggle",
"template",
"tap",
"info",
"group",
"numeric"
]
}
}
},
{
"if": {
"properties": {
"type": {
"const": "toggle"
}
}
},
"then": {
"$ref": "#/$defs/toggle"
},
"else": {
"if": {
"properties": {
"type": {
"const": "template"
}
}
},
"then": {
"$ref": "#/$defs/template"
},
"else": {
"if": {
"properties": {
"type": {
"const": "tap"
}
}
},
"then": {
"$ref": "#/$defs/tap"
},
"else": {
"if": {
"properties": {
"type": {
"const": "info"
}
}
},
"then": {
"$ref": "#/$defs/info"
},
"else": {
"if": {
"properties": {
"type": {
"const": "group"
}
}
},
"then": {
"$ref": "#/$defs/group"
},
"else": {
"if": {
"properties": {
"type": {
"const": "numeric"
}
}
},
"then": {
"$ref": "#/$defs/numeric"
}
}
}
}
}
}
}
]
}
},
"name": {
"title": "Your familiar name to display in the menu item",
"type": "string"
},
"entity": {
"type": "string",
"title": "Home Assistant entity name",
"pattern": "^[^.]+\\.[^.]+$"
},
"action": {
"type": "string",
"title": "Home Assistant action name",
"pattern": "^[^.]+\\.[^.]+$"
},
"tap_action_tap": {
"allOf": [
{
"title": "Tap Action",
"description": "'confirm' and 'pin' fields are optional. 'action' is required.",
"properties": {
"service": {
"$ref": "#/$defs/action",
"deprecated": true
},
"action": {
"$ref": "#/$defs/action"
},
"data": {
"type": "object",
"title": "Your actions's parameters",
"description": "The object containing the parameters and their values to be passed to the entity. No schema checking can be done here, you are on your own! On application crash, remove the parameters."
}
},
"oneOf": [
{
"required": [
"action"
],
"not": {
"required": [
"service"
]
}
},
{
"required": [
"service"
]
}
]
},
{
"$ref": "#/$defs/tap_action"
}
]
},
"tap_action": {
"type": "object",
"title": "Tap Action",
"description": "'confirm' and 'pin' fields are optional.",
"properties": {
"confirm": {
"$ref": "#/$defs/confirm"
},
"pin": {
"$ref": "#/$defs/pin"
},
"exit": {
"$ref": "#/$defs/exit"
}
}
},
"content": {
"title": "Home Assistant Template",
"description": "Jinja2 template defining the text to display. Must be included in an 'info'. Optional in a 'toggle', 'tap', 'numeric' and 'group'. Special characters may not render in the glance context.",
"type": "string"
},
"confirm": {
"type": [
"boolean",
"string"
],
"default": false,
"title": "Confirmation",
"description": "Optional confirmation of the action before execution as a precaution. Use a Boolean for the default message. Specify a string to display a specific confirmation message."
},
"pin": {
"type": "boolean",
"default": false,
"title": "PIN Confirmation",
"description": "Optional PIN confirmation of the action before execution as a precaution. Has precedence over 'confirm': true if both are set."
},
"glance": {
"type": "object",
"title": "Glance customisation",
"oneOf": [
{
"properties": {
"type": {
"title": "Glance type",
"description": "One of 'info' or 'status'. 'info' renders the template specified in the 'content' field inside the glance view. 'status' reverts to the default glance view and ignores the 'content' field. This allows for disabling the template temporarily.",
"const": "info"
},
"content": {
"$ref": "#/$defs/content"
}
},
"required": [
"type",
"content"
]
},
{
"properties": {
"type": {
"title": "Glance type",
"description": "One of 'info' or 'status'.",
"const": "status"
}
},
"required": [
"type"
]
}
]
},
"enabled": {
"type": "boolean",
"default": true,
"title": "Enable the menu item",
"description": "Typically used to temporarily disable a menu item, e.g. for seasonal variations. Enabled (true) by default."
},
"exit": {
"type": "boolean",
"default": false,
"title": "Exit on selection",
"description": "Choose to exit the application after this item has been selected. Disabled (false) by default. N.B. Only actionable menu items can have this field added."
}
}
}