{
  "pluginAlias": "HomebridgeSsh",
  "pluginType": "platform",
  "singular": true,
  "customUi": true,
  "headerDisplay": "Exposes remote shell scripts (run over SSH) as native HomeKit accessories.",
  "footerDisplay": "Configuration reference: https://github.com/x-dragos/homebridge-ssh-platform#configuration",
  "schema": {
    "type": "object",
    "required": ["name"],
    "properties": {
      "name": {
        "title": "Bridge name",
        "type": "string",
        "default": "SSH Bridge"
      },
      "logLevel": {
        "title": "Log level",
        "type": "string",
        "default": "info",
        "oneOf": [
          { "title": "Debug", "enum": ["debug"] },
          { "title": "Info", "enum": ["info"] },
          { "title": "Warn", "enum": ["warn"] },
          { "title": "Error", "enum": ["error"] }
        ]
      },
      "hosts": {
        "title": "Hosts",
        "type": "array",
        "minItems": 1,
        "items": {
          "title": "Host",
          "type": "object",
          "required": ["id", "ssh"],
          "properties": {
            "id": {
              "title": "Host ID",
              "description": "Stable identifier referenced by accessories (lowercase, dashes ok).",
              "type": "string",
              "pattern": "^[a-z0-9][a-z0-9-]*$"
            },
            "ssh": {
              "title": "SSH connection",
              "type": "object",
              "required": ["host", "user", "auth"],
              "properties": {
                "host": {
                  "title": "Hostname or IP",
                  "type": "string"
                },
                "port": {
                  "title": "Port",
                  "type": "integer",
                  "default": 22,
                  "minimum": 1,
                  "maximum": 65535
                },
                "user": {
                  "title": "User",
                  "type": "string"
                },
                "auth": {
                  "title": "Authentication",
                  "type": "object",
                  "required": ["method"],
                  "properties": {
                    "method": {
                      "title": "Method",
                      "type": "string",
                      "default": "key",
                      "oneOf": [
                        { "title": "SSH key", "enum": ["key"] },
                        { "title": "Password", "enum": ["password"] },
                        { "title": "SSH agent", "enum": ["agent"] }
                      ]
                    },
                    "privateKeyPath": {
                      "title": "Private key path",
                      "type": "string",
                      "condition": {
                        "functionBody": "return model.hosts && model.hosts[arrayIndices[0]] && model.hosts[arrayIndices[0]].ssh && model.hosts[arrayIndices[0]].ssh.auth && model.hosts[arrayIndices[0]].ssh.auth.method === 'key';"
                      }
                    },
                    "passphrase": {
                      "title": "Passphrase (if key is encrypted)",
                      "type": "string",
                      "format": "password",
                      "condition": {
                        "functionBody": "return model.hosts && model.hosts[arrayIndices[0]] && model.hosts[arrayIndices[0]].ssh && model.hosts[arrayIndices[0]].ssh.auth && model.hosts[arrayIndices[0]].ssh.auth.method === 'key';"
                      }
                    },
                    "password": {
                      "title": "Password",
                      "type": "string",
                      "format": "password",
                      "condition": {
                        "functionBody": "return model.hosts && model.hosts[arrayIndices[0]] && model.hosts[arrayIndices[0]].ssh && model.hosts[arrayIndices[0]].ssh.auth && model.hosts[arrayIndices[0]].ssh.auth.method === 'password';"
                      }
                    }
                  }
                },
                "connectTimeoutMs": {
                  "title": "Connect timeout (ms)",
                  "type": "integer",
                  "placeholder": 10000,
                  "minimum": 1,
                  "maximum": 60000
                },
                "keepaliveIntervalMs": {
                  "title": "Keepalive interval (ms)",
                  "type": "integer",
                  "placeholder": 30000,
                  "minimum": 0,
                  "maximum": 300000
                },
                "idleDisconnectMs": {
                  "title": "Idle disconnect (ms, 0 = never)",
                  "type": "integer",
                  "placeholder": 0,
                  "minimum": 0,
                  "maximum": 86400000
                }
              }
            }
          }
        }
      },
      "accessories": {
        "title": "Accessories",
        "type": "array",
        "items": {
          "title": "Accessory",
          "type": "object",
          "required": ["type", "name", "host"],
          "properties": {
            "type": {
              "title": "Type",
              "type": "string",
              "default": "switch",
              "oneOf": [
                { "title": "Switch", "enum": ["switch"] },
                { "title": "Garage door", "enum": ["garageDoor"] }
              ]
            },
            "name": {
              "title": "Name",
              "type": "string"
            },
            "host": {
              "title": "Host ID",
              "description": "Must match a host id defined above.",
              "type": "string"
            },
            "commands": {
              "title": "Commands",
              "type": "object",
              "properties": {
                "on": {
                  "title": "On / open command",
                  "type": "object",
                  "required": ["command"],
                  "properties": {
                    "command": { "title": "Command", "type": "string" },
                    "timeoutMs": {
                      "title": "Timeout (ms)",
                      "type": "integer",
                      "placeholder": 5000,
                      "minimum": 1,
                      "maximum": 120000
                    }
                  }
                },
                "off": {
                  "title": "Off / close command",
                  "type": "object",
                  "properties": {
                    "command": { "title": "Command", "type": "string" },
                    "timeoutMs": {
                      "title": "Timeout (ms)",
                      "type": "integer",
                      "placeholder": 5000,
                      "minimum": 1,
                      "maximum": 120000
                    }
                  }
                },
                "state": {
                  "title": "State command (optional)",
                  "type": "object",
                  "properties": {
                    "command": { "title": "Command", "type": "string" },
                    "timeoutMs": {
                      "title": "Timeout (ms)",
                      "type": "integer",
                      "placeholder": 3000,
                      "minimum": 1,
                      "maximum": 120000
                    }
                  }
                }
              }
            },
            "behavior": {
              "title": "Switch behavior",
              "type": "object",
              "condition": {
                "functionBody": "return model.accessories && model.accessories[arrayIndices[0]] && model.accessories[arrayIndices[0]].type === 'switch';"
              },
              "properties": {
                "mode": {
                  "title": "Mode",
                  "type": "string",
                  "default": "stateful",
                  "oneOf": [
                    { "title": "Stateful (on/off persists)", "enum": ["stateful"] },
                    { "title": "Momentary (auto-reset)", "enum": ["momentary"] }
                  ]
                },
                "autoResetMs": {
                  "title": "Auto-reset delay (ms)",
                  "type": "integer",
                  "placeholder": 1000,
                  "minimum": 50,
                  "maximum": 60000,
                  "condition": {
                    "functionBody": "return model.accessories && model.accessories[arrayIndices[0]] && model.accessories[arrayIndices[0]].behavior && model.accessories[arrayIndices[0]].behavior.mode === 'momentary';"
                  }
                }
              }
            },
            "state": {
              "title": "State polling (switch, optional)",
              "type": "object",
              "condition": {
                "functionBody": "return model.accessories && model.accessories[arrayIndices[0]] && model.accessories[arrayIndices[0]].type === 'switch';"
              },
              "properties": {
                "command": {
                  "type": "object",
                  "properties": {
                    "command": { "title": "Command", "type": "string" },
                    "timeoutMs": {
                      "title": "Timeout (ms)",
                      "type": "integer",
                      "placeholder": 3000,
                      "minimum": 1,
                      "maximum": 120000
                    }
                  }
                },
                "onValue": { "title": "On value", "type": "string" },
                "matchMode": {
                  "title": "Match mode",
                  "type": "string",
                  "default": "exact",
                  "oneOf": [
                    { "title": "Exact", "enum": ["exact"] },
                    { "title": "Contains", "enum": ["contains"] },
                    { "title": "Regex", "enum": ["regex"] }
                  ]
                },
                "pollIntervalMs": {
                  "title": "Poll interval (ms, 0 = no polling)",
                  "type": "integer",
                  "placeholder": 0,
                  "minimum": 0,
                  "maximum": 3600000
                }
              }
            },
            "stateMapping": {
              "title": "Garage state mapping",
              "type": "object",
              "condition": {
                "functionBody": "return model.accessories && model.accessories[arrayIndices[0]] && model.accessories[arrayIndices[0]].type === 'garageDoor';"
              },
              "properties": {
                "open": {
                  "type": "object",
                  "properties": {
                    "match": { "title": "Match", "type": "string" },
                    "mode": {
                      "title": "Mode",
                      "type": "string",
                      "oneOf": [
                        { "title": "Exact", "enum": ["exact"] },
                        { "title": "Contains", "enum": ["contains"] },
                        { "title": "Regex", "enum": ["regex"] }
                      ]
                    }
                  }
                },
                "closed": {
                  "type": "object",
                  "properties": {
                    "match": { "title": "Match", "type": "string" },
                    "mode": {
                      "title": "Mode",
                      "type": "string",
                      "oneOf": [
                        { "title": "Exact", "enum": ["exact"] },
                        { "title": "Contains", "enum": ["contains"] },
                        { "title": "Regex", "enum": ["regex"] }
                      ]
                    }
                  }
                }
              }
            },
            "timing": {
              "title": "Garage timing",
              "type": "object",
              "condition": {
                "functionBody": "return model.accessories && model.accessories[arrayIndices[0]] && model.accessories[arrayIndices[0]].type === 'garageDoor';"
              },
              "properties": {
                "openTravelTimeMs": {
                  "title": "Open travel time (ms)",
                  "type": "integer",
                  "placeholder": 0,
                  "minimum": 0,
                  "maximum": 120000
                },
                "closeTravelTimeMs": {
                  "title": "Close travel time (ms)",
                  "type": "integer",
                  "placeholder": 0,
                  "minimum": 0,
                  "maximum": 120000
                },
                "autoCloseTimeoutMs": {
                  "title": "Auto-close timeout (ms, 0 = disabled)",
                  "description": "How long the door stays open after reaching the open position before auto-closing. 0 disables auto-close.",
                  "type": "integer",
                  "placeholder": 0,
                  "minimum": 0,
                  "maximum": 86400000
                },
                "autoCloseMode": {
                  "title": "Auto-close mode",
                  "description": "Choose who closes the door after the auto-close timeout: the plugin (it runs the close command) or the door itself (the plugin only mirrors the closing state in HomeKit).",
                  "type": "string",
                  "default": "execute",
                  "oneOf": [
                    { "title": "Plugin runs close command", "enum": ["execute"] },
                    { "title": "Hardware closes itself (state-only)", "enum": ["simulated"] }
                  ],
                  "condition": {
                    "functionBody": "return model.accessories && model.accessories[arrayIndices[0]] && model.accessories[arrayIndices[0]].timing && model.accessories[arrayIndices[0]].timing.autoCloseTimeoutMs > 0;"
                  }
                },
                "statePollIntervalMs": {
                  "title": "Status check interval (ms, 0 = disabled)",
                  "description": "How often to check the door's status while it is parked, to keep HomeKit in sync if it changes outside of HomeKit (manual button, fault, hardware auto-close).",
                  "type": "integer",
                  "placeholder": 0,
                  "minimum": 0,
                  "maximum": 3600000
                },
                "transientPollIntervalMs": {
                  "title": "Transient poll interval (ms, 0 = use state poll interval)",
                  "description": "How often to check the door's status while it is opening or closing. A short interval shows fresh progress in HomeKit without keeping the connection busy when the door is parked. 0 reuses the regular interval.",
                  "type": "integer",
                  "placeholder": 1000,
                  "minimum": 0,
                  "maximum": 60000
                },
                "postCommandPollDelayMs": {
                  "title": "Post-command poll delay (ms)",
                  "description": "Wait this long after an open or close command before checking the door's status again. Gives the door a moment to report its new state. 0 disables the grace.",
                  "type": "integer",
                  "placeholder": 5000,
                  "minimum": 0,
                  "maximum": 60000
                }
              }
            }
          }
        }
      }
    }
  }
}
