Compare commits
10 Commits
smithery/c
...
v0.2.7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3256682ba | ||
|
|
7635cce15a | ||
|
|
53a041921b | ||
|
|
af3399515a | ||
|
|
01991c0060 | ||
|
|
3f8d67b145 | ||
|
|
ab8b597843 | ||
|
|
ddf9070a64 | ||
|
|
b9727981cc | ||
|
|
e1db799b1d |
11
Dockerfile
11
Dockerfile
@@ -17,13 +17,15 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
|
|
||||||
# Set build-time environment variables
|
# Set build-time environment variables
|
||||||
ENV NODE_ENV=production \
|
ENV NODE_ENV=production \
|
||||||
NODE_OPTIONS="--max-old-space-size=2048"
|
NODE_OPTIONS="--max-old-space-size=2048" \
|
||||||
|
BUN_INSTALL_CACHE=0
|
||||||
|
|
||||||
# Copy only package files first
|
# Copy only package files first
|
||||||
COPY package.json ./
|
COPY package.json ./
|
||||||
|
|
||||||
# Install dependencies without lockfile
|
# Install dependencies with a clean slate
|
||||||
RUN bun install --no-cache
|
RUN rm -rf node_modules .bun bun.lockb && \
|
||||||
|
bun install --no-save
|
||||||
|
|
||||||
# Copy source files and build
|
# Copy source files and build
|
||||||
COPY src ./src
|
COPY src ./src
|
||||||
@@ -51,6 +53,9 @@ COPY --from=builder --chown=bunjs:nodejs /app/dist ./dist
|
|||||||
COPY --from=builder --chown=bunjs:nodejs /app/node_modules ./node_modules
|
COPY --from=builder --chown=bunjs:nodejs /app/node_modules ./node_modules
|
||||||
COPY --chown=bunjs:nodejs package.json ./
|
COPY --chown=bunjs:nodejs package.json ./
|
||||||
|
|
||||||
|
# Create logs directory with proper permissions
|
||||||
|
RUN mkdir -p /app/logs && chown -R bunjs:nodejs /app/logs
|
||||||
|
|
||||||
# Switch to non-root user
|
# Switch to non-root user
|
||||||
USER bunjs
|
USER bunjs
|
||||||
|
|
||||||
|
|||||||
84
README.md
84
README.md
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
Welcome to the **Model Context Protocol (MCP) Server for Home Assistant**! This robust platform bridges Home Assistant with cutting-edge Language Learning Models (LLMs), enabling natural language interactions and real-time automation of your smart devices. Imagine entering your home, saying:
|
Welcome to the **Model Context Protocol (MCP) Server for Home Assistant**! This robust platform bridges Home Assistant with cutting-edge Language Learning Models (LLMs), enabling natural language interactions and real-time automation of your smart devices. Imagine entering your home, saying:
|
||||||
|
|
||||||
> “Hey MCP, dim the lights and start my evening playlist,”
|
> "Hey MCP, dim the lights and start my evening playlist,"
|
||||||
|
|
||||||
and watching your home transform instantly—that's the magic that MCP Server delivers!
|
and watching your home transform instantly—that's the magic that MCP Server delivers!
|
||||||
|
|
||||||
@@ -58,17 +58,17 @@ Our architecture is engineered for performance, scalability, and security. The f
|
|||||||
```mermaid
|
```mermaid
|
||||||
graph TD
|
graph TD
|
||||||
subgraph Client
|
subgraph Client
|
||||||
A[Client Application<br/>(Web / Mobile / Voice)]
|
A[Client Application<br>(Web / Mobile / Voice)]
|
||||||
end
|
end
|
||||||
subgraph CDN
|
subgraph CDN
|
||||||
B[CDN / Cache]
|
B[CDN / Cache]
|
||||||
end
|
end
|
||||||
subgraph Server
|
subgraph Server
|
||||||
C[Bun Native Server]
|
C[Bun Native Server]
|
||||||
E[NLP Engine<br/>& Language Processing Module]
|
E[NLP Engine &<br>Language Processing Module]
|
||||||
end
|
end
|
||||||
subgraph Integration
|
subgraph Integration
|
||||||
D[Home Assistant<br/>(Devices, Lights, Thermostats)]
|
D[Home Assistant<br>(Devices, Lights, Thermostats)]
|
||||||
end
|
end
|
||||||
|
|
||||||
A -->|HTTP Request| B
|
A -->|HTTP Request| B
|
||||||
@@ -294,3 +294,79 @@ This project is licensed under the MIT License. See [LICENSE](LICENSE) for full
|
|||||||
---
|
---
|
||||||
|
|
||||||
🔋 Batteries included.
|
🔋 Batteries included.
|
||||||
|
|
||||||
|
## MCP Client Integration
|
||||||
|
|
||||||
|
This MCP server can be integrated with various clients that support the Model Context Protocol. Below are instructions for different client integrations:
|
||||||
|
|
||||||
|
### Cursor Integration
|
||||||
|
|
||||||
|
The server can be integrated with Cursor by adding the configuration to `.cursor/config/config.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"homeassistant-mcp": {
|
||||||
|
"command": "bun",
|
||||||
|
"args": ["run", "start"],
|
||||||
|
"cwd": "${workspaceRoot}",
|
||||||
|
"env": {
|
||||||
|
"NODE_ENV": "development"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Claude Desktop Integration
|
||||||
|
|
||||||
|
For Claude Desktop, add the following to your Claude configuration file:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"homeassistant-mcp": {
|
||||||
|
"command": "bun",
|
||||||
|
"args": ["run", "start", "--port", "8080"],
|
||||||
|
"env": {
|
||||||
|
"NODE_ENV": "production"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cline Integration
|
||||||
|
|
||||||
|
For Cline-based clients, add the following configuration:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"homeassistant-mcp": {
|
||||||
|
"command": "bun",
|
||||||
|
"args": [
|
||||||
|
"run",
|
||||||
|
"start",
|
||||||
|
"--enable-cline",
|
||||||
|
"--config",
|
||||||
|
"${configDir}/.env"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"NODE_ENV": "production",
|
||||||
|
"CLINE_MODE": "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Command Line Usage
|
||||||
|
|
||||||
|
#### Windows
|
||||||
|
A CMD script is provided in the `scripts` directory. To use it:
|
||||||
|
|
||||||
|
1. Navigate to the `scripts` directory
|
||||||
|
2. Run `start_mcp.cmd`
|
||||||
|
|
||||||
|
The script will start the MCP server with default configuration.
|
||||||
|
|||||||
309
bun.lock
Normal file → Executable file
309
bun.lock
Normal file → Executable file
@@ -1,8 +1,7 @@
|
|||||||
{
|
{
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 0,
|
||||||
"workspaces": {
|
"workspaces": {
|
||||||
"": {
|
"": {
|
||||||
"name": "homeassistant-mcp",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@elysiajs/cors": "^1.2.0",
|
"@elysiajs/cors": "^1.2.0",
|
||||||
"@elysiajs/swagger": "^1.2.0",
|
"@elysiajs/swagger": "^1.2.0",
|
||||||
@@ -17,6 +16,8 @@
|
|||||||
"node-fetch": "^3.3.2",
|
"node-fetch": "^3.3.2",
|
||||||
"sanitize-html": "^2.11.0",
|
"sanitize-html": "^2.11.0",
|
||||||
"typescript": "^5.3.3",
|
"typescript": "^5.3.3",
|
||||||
|
"winston": "^3.11.0",
|
||||||
|
"winston-daily-rotate-file": "^5.0.0",
|
||||||
"ws": "^8.16.0",
|
"ws": "^8.16.0",
|
||||||
"zod": "^3.22.4",
|
"zod": "^3.22.4",
|
||||||
},
|
},
|
||||||
@@ -36,6 +37,10 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"packages": {
|
"packages": {
|
||||||
|
"@colors/colors": ["@colors/colors@1.6.0", "", {}, "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA=="],
|
||||||
|
|
||||||
|
"@dabh/diagnostics": ["@dabh/diagnostics@2.0.3", "", { "dependencies": { "colorspace": "1.1.x", "enabled": "2.0.x", "kuler": "^2.0.0" } }, "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA=="],
|
||||||
|
|
||||||
"@elysiajs/cors": ["@elysiajs/cors@1.2.0", "", { "peerDependencies": { "elysia": ">= 1.2.0" } }, "sha512-qsJwDAg6WfdQRMfj6uSMcDPSpXvm/zQFeAX1uuJXhIgazH8itSfcDxcH9pMuXVRX1yQNi2pPwNQLJmAcw5mzvw=="],
|
"@elysiajs/cors": ["@elysiajs/cors@1.2.0", "", { "peerDependencies": { "elysia": ">= 1.2.0" } }, "sha512-qsJwDAg6WfdQRMfj6uSMcDPSpXvm/zQFeAX1uuJXhIgazH8itSfcDxcH9pMuXVRX1yQNi2pPwNQLJmAcw5mzvw=="],
|
||||||
|
|
||||||
"@elysiajs/swagger": ["@elysiajs/swagger@1.2.0", "", { "dependencies": { "@scalar/themes": "^0.9.52", "@scalar/types": "^0.0.12", "openapi-types": "^12.1.3", "pathe": "^1.1.2" }, "peerDependencies": { "elysia": ">= 1.2.0" } }, "sha512-OPx93DP6rM2VHjA3D44Xiz5MYm9AYlO2NGWPsnSsdyvaOCiL9wJj529583h7arX4iIEYE5LiLB0/A45unqbopw=="],
|
"@elysiajs/swagger": ["@elysiajs/swagger@1.2.0", "", { "dependencies": { "@scalar/themes": "^0.9.52", "@scalar/types": "^0.0.12", "openapi-types": "^12.1.3", "pathe": "^1.1.2" }, "peerDependencies": { "elysia": ">= 1.2.0" } }, "sha512-OPx93DP6rM2VHjA3D44Xiz5MYm9AYlO2NGWPsnSsdyvaOCiL9wJj529583h7arX4iIEYE5LiLB0/A45unqbopw=="],
|
||||||
@@ -70,17 +75,19 @@
|
|||||||
|
|
||||||
"@sinclair/typebox": ["@sinclair/typebox@0.34.15", "", {}, "sha512-xeIzl3h1Znn9w/LTITqpiwag0gXjA+ldi2ZkXIBxGEppGCW211Tza+eL6D4pKqs10bj5z2umBWk5WL6spQ2OCQ=="],
|
"@sinclair/typebox": ["@sinclair/typebox@0.34.15", "", {}, "sha512-xeIzl3h1Znn9w/LTITqpiwag0gXjA+ldi2ZkXIBxGEppGCW211Tza+eL6D4pKqs10bj5z2umBWk5WL6spQ2OCQ=="],
|
||||||
|
|
||||||
"@types/jsonwebtoken": ["@types/jsonwebtoken@9.0.8", "", { "dependencies": { "@types/ms": "*", "@types/node": "*" } }, ""],
|
"@types/jsonwebtoken": ["@types/jsonwebtoken@9.0.8", "", { "dependencies": { "@types/ms": "*", "@types/node": "*" } }, "sha512-7fx54m60nLFUVYlxAB1xpe9CBWX2vSrk50Y6ogRJ1v5xxtba7qXTg5BgYDN5dq+yuQQ9HaVlHJyAAt1/mxryFg=="],
|
||||||
|
|
||||||
"@types/ms": ["@types/ms@2.1.0", "", {}, ""],
|
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
|
||||||
|
|
||||||
"@types/node": ["@types/node@20.17.16", "", { "dependencies": { "undici-types": "~6.19.2" } }, ""],
|
"@types/node": ["@types/node@20.17.17", "", { "dependencies": { "undici-types": "~6.19.2" } }, "sha512-/WndGO4kIfMicEQLTi/mDANUu/iVUhT7KboZPdEqqHQ4aTS+3qT3U5gIqWDFV+XouorjfgGqvKILJeHhuQgFYg=="],
|
||||||
|
|
||||||
"@types/sanitize-html": ["@types/sanitize-html@2.13.0", "", { "dependencies": { "htmlparser2": "^8.0.0" } }, "sha512-X31WxbvW9TjIhZZNyNBZ/p5ax4ti7qsNDBDEnH4zAgmEh35YnFD1UiS6z9Cd34kKm0LslFW0KPmTQzu/oGtsqQ=="],
|
"@types/sanitize-html": ["@types/sanitize-html@2.13.0", "", { "dependencies": { "htmlparser2": "^8.0.0" } }, "sha512-X31WxbvW9TjIhZZNyNBZ/p5ax4ti7qsNDBDEnH4zAgmEh35YnFD1UiS6z9Cd34kKm0LslFW0KPmTQzu/oGtsqQ=="],
|
||||||
|
|
||||||
|
"@types/triple-beam": ["@types/triple-beam@1.3.5", "", {}, "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw=="],
|
||||||
|
|
||||||
"@types/uuid": ["@types/uuid@10.0.0", "", {}, "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ=="],
|
"@types/uuid": ["@types/uuid@10.0.0", "", {}, "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ=="],
|
||||||
|
|
||||||
"@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, ""],
|
"@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="],
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@7.18.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "7.18.0", "@typescript-eslint/type-utils": "7.18.0", "@typescript-eslint/utils": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^1.3.0" }, "peerDependencies": { "@typescript-eslint/parser": "^7.0.0", "eslint": "^8.56.0" } }, "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw=="],
|
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@7.18.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "7.18.0", "@typescript-eslint/type-utils": "7.18.0", "@typescript-eslint/utils": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^1.3.0" }, "peerDependencies": { "@typescript-eslint/parser": "^7.0.0", "eslint": "^8.56.0" } }, "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw=="],
|
||||||
|
|
||||||
@@ -102,57 +109,65 @@
|
|||||||
|
|
||||||
"@unhead/schema": ["@unhead/schema@1.11.18", "", { "dependencies": { "hookable": "^5.5.3", "zhead": "^2.2.4" } }, "sha512-a3TA/OJCRdfbFhcA3Hq24k1ZU1o9szicESrw8DZcGyQFacHnh84mVgnyqSkMnwgCmfN4kvjSiTBlLEHS6+wATw=="],
|
"@unhead/schema": ["@unhead/schema@1.11.18", "", { "dependencies": { "hookable": "^5.5.3", "zhead": "^2.2.4" } }, "sha512-a3TA/OJCRdfbFhcA3Hq24k1ZU1o9szicESrw8DZcGyQFacHnh84mVgnyqSkMnwgCmfN4kvjSiTBlLEHS6+wATw=="],
|
||||||
|
|
||||||
"acorn": ["acorn@8.14.0", "", { "bin": "bin/acorn" }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="],
|
"acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="],
|
||||||
|
|
||||||
"acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
|
"acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
|
||||||
|
|
||||||
"ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
|
"ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
|
||||||
|
|
||||||
"ansi-regex": ["ansi-regex@5.0.1", "", {}, ""],
|
"ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||||
|
|
||||||
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
||||||
|
|
||||||
"argparse": ["argparse@2.0.1", "", {}, ""],
|
"argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
|
||||||
|
|
||||||
"array-union": ["array-union@2.1.0", "", {}, "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="],
|
"array-union": ["array-union@2.1.0", "", {}, "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="],
|
||||||
|
|
||||||
"asap": ["asap@2.0.6", "", {}, ""],
|
"asap": ["asap@2.0.6", "", {}, "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="],
|
||||||
|
|
||||||
"asynckit": ["asynckit@0.4.0", "", {}, ""],
|
"async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="],
|
||||||
|
|
||||||
"balanced-match": ["balanced-match@1.0.2", "", {}, ""],
|
"asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="],
|
||||||
|
|
||||||
|
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
||||||
|
|
||||||
"brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="],
|
"brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="],
|
||||||
|
|
||||||
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, ""],
|
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
|
||||||
|
|
||||||
"buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, ""],
|
"buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="],
|
||||||
|
|
||||||
"bun-types": ["bun-types@1.2.2", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-RCbMH5elr9gjgDGDhkTTugA21XtJAy/9jkKe/G3WR2q17VPGhcquf9Sir6uay9iW+7P/BV0CAHA1XlHXMAVKHg=="],
|
"bun-types": ["bun-types@1.2.2", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-RCbMH5elr9gjgDGDhkTTugA21XtJAy/9jkKe/G3WR2q17VPGhcquf9Sir6uay9iW+7P/BV0CAHA1XlHXMAVKHg=="],
|
||||||
|
|
||||||
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.1", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, ""],
|
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.1", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g=="],
|
||||||
|
|
||||||
"call-bound": ["call-bound@1.0.3", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "get-intrinsic": "^1.2.6" } }, ""],
|
"call-bound": ["call-bound@1.0.3", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "get-intrinsic": "^1.2.6" } }, "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA=="],
|
||||||
|
|
||||||
"callsites": ["callsites@3.1.0", "", {}, ""],
|
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
|
||||||
|
|
||||||
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
|
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
|
||||||
|
|
||||||
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, ""],
|
"color": ["color@3.2.1", "", { "dependencies": { "color-convert": "^1.9.3", "color-string": "^1.6.0" } }, "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA=="],
|
||||||
|
|
||||||
"color-name": ["color-name@1.1.4", "", {}, ""],
|
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
|
||||||
|
|
||||||
"combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, ""],
|
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
|
||||||
|
|
||||||
"component-emitter": ["component-emitter@1.3.1", "", {}, ""],
|
"color-string": ["color-string@1.9.1", "", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="],
|
||||||
|
|
||||||
"concat-map": ["concat-map@0.0.1", "", {}, ""],
|
"colorspace": ["colorspace@1.1.4", "", { "dependencies": { "color": "^3.1.3", "text-hex": "1.0.x" } }, "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w=="],
|
||||||
|
|
||||||
|
"combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="],
|
||||||
|
|
||||||
|
"component-emitter": ["component-emitter@1.3.1", "", {}, "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ=="],
|
||||||
|
|
||||||
|
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
|
||||||
|
|
||||||
"cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="],
|
"cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="],
|
||||||
|
|
||||||
"cookiejar": ["cookiejar@2.1.4", "", {}, ""],
|
"cookiejar": ["cookiejar@2.1.4", "", {}, "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw=="],
|
||||||
|
|
||||||
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, ""],
|
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
||||||
|
|
||||||
"data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="],
|
"data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="],
|
||||||
|
|
||||||
@@ -160,11 +175,11 @@
|
|||||||
|
|
||||||
"deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
|
"deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
|
||||||
|
|
||||||
"deepmerge": ["deepmerge@4.3.1", "", {}, ""],
|
"deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="],
|
||||||
|
|
||||||
"delayed-stream": ["delayed-stream@1.0.0", "", {}, ""],
|
"delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="],
|
||||||
|
|
||||||
"dezalgo": ["dezalgo@1.0.4", "", { "dependencies": { "asap": "^2.0.0", "wrappy": "1" } }, ""],
|
"dezalgo": ["dezalgo@1.0.4", "", { "dependencies": { "asap": "^2.0.0", "wrappy": "1" } }, "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig=="],
|
||||||
|
|
||||||
"dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="],
|
"dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="],
|
||||||
|
|
||||||
@@ -178,29 +193,31 @@
|
|||||||
|
|
||||||
"domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="],
|
"domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="],
|
||||||
|
|
||||||
"dotenv": ["dotenv@16.4.7", "", {}, ""],
|
"dotenv": ["dotenv@16.4.7", "", {}, "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ=="],
|
||||||
|
|
||||||
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, ""],
|
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
|
||||||
|
|
||||||
"ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, ""],
|
"ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="],
|
||||||
|
|
||||||
"elysia": ["elysia@1.2.12", "", { "dependencies": { "@sinclair/typebox": "^0.34.15", "cookie": "^1.0.2", "memoirist": "^0.3.0", "openapi-types": "^12.1.3" }, "peerDependencies": { "typescript": ">= 5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-X1bZo09qe8/Poa/5tz08Y+sE/77B/wLwnA5xDDENU3FCrsUtYJuBVcy6BPXGRCgnJ1fPQpc0Ov2ZU5MYJXluTg=="],
|
"elysia": ["elysia@1.2.12", "", { "dependencies": { "@sinclair/typebox": "^0.34.15", "cookie": "^1.0.2", "memoirist": "^0.3.0", "openapi-types": "^12.1.3" }, "peerDependencies": { "typescript": ">= 5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-X1bZo09qe8/Poa/5tz08Y+sE/77B/wLwnA5xDDENU3FCrsUtYJuBVcy6BPXGRCgnJ1fPQpc0Ov2ZU5MYJXluTg=="],
|
||||||
|
|
||||||
|
"enabled": ["enabled@2.0.0", "", {}, "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ=="],
|
||||||
|
|
||||||
"entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
|
"entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
|
||||||
|
|
||||||
"es-define-property": ["es-define-property@1.0.1", "", {}, ""],
|
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
|
||||||
|
|
||||||
"es-errors": ["es-errors@1.3.0", "", {}, ""],
|
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
|
||||||
|
|
||||||
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, ""],
|
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
|
||||||
|
|
||||||
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
|
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
|
||||||
|
|
||||||
"eslint": ["eslint@8.57.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", "@eslint/js": "8.57.1", "@humanwhocodes/config-array": "^0.13.0", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.2.2", "eslint-visitor-keys": "^3.4.3", "espree": "^9.6.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3", "strip-ansi": "^6.0.1", "text-table": "^0.2.0" }, "bin": "bin/eslint.js" }, "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA=="],
|
"eslint": ["eslint@8.57.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", "@eslint/js": "8.57.1", "@humanwhocodes/config-array": "^0.13.0", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.2.2", "eslint-visitor-keys": "^3.4.3", "espree": "^9.6.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3", "strip-ansi": "^6.0.1", "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" } }, "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA=="],
|
||||||
|
|
||||||
"eslint-config-prettier": ["eslint-config-prettier@9.1.0", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": "bin/cli.js" }, "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw=="],
|
"eslint-config-prettier": ["eslint-config-prettier@9.1.0", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": { "eslint-config-prettier": "bin/cli.js" } }, "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw=="],
|
||||||
|
|
||||||
"eslint-plugin-prettier": ["eslint-plugin-prettier@5.2.3", "", { "dependencies": { "prettier-linter-helpers": "^1.0.0", "synckit": "^0.9.1" }, "peerDependencies": { "@types/eslint": ">=8.0.0", "eslint": ">=8.0.0", "eslint-config-prettier": "*", "prettier": ">=3.0.0" }, "optionalPeers": ["@types/eslint"] }, "sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw=="],
|
"eslint-plugin-prettier": ["eslint-plugin-prettier@5.2.3", "", { "dependencies": { "prettier-linter-helpers": "^1.0.0", "synckit": "^0.9.1" }, "peerDependencies": { "@types/eslint": ">=8.0.0", "eslint": ">=8.0.0", "eslint-config-prettier": "*", "prettier": ">=3.0.0" }, "optionalPeers": ["@types/eslint", "eslint-config-prettier"] }, "sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw=="],
|
||||||
|
|
||||||
"eslint-scope": ["eslint-scope@7.2.2", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg=="],
|
"eslint-scope": ["eslint-scope@7.2.2", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg=="],
|
||||||
|
|
||||||
@@ -216,25 +233,29 @@
|
|||||||
|
|
||||||
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
|
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
|
||||||
|
|
||||||
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, ""],
|
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
||||||
|
|
||||||
"fast-diff": ["fast-diff@1.3.0", "", {}, "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="],
|
"fast-diff": ["fast-diff@1.3.0", "", {}, "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="],
|
||||||
|
|
||||||
"fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
|
"fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
|
||||||
|
|
||||||
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, ""],
|
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
|
||||||
|
|
||||||
"fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="],
|
"fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="],
|
||||||
|
|
||||||
"fast-safe-stringify": ["fast-safe-stringify@2.1.1", "", {}, ""],
|
"fast-safe-stringify": ["fast-safe-stringify@2.1.1", "", {}, "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="],
|
||||||
|
|
||||||
"fastq": ["fastq@1.19.0", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA=="],
|
"fastq": ["fastq@1.19.0", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA=="],
|
||||||
|
|
||||||
|
"fecha": ["fecha@4.2.3", "", {}, "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="],
|
||||||
|
|
||||||
"fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="],
|
"fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="],
|
||||||
|
|
||||||
"file-entry-cache": ["file-entry-cache@6.0.1", "", { "dependencies": { "flat-cache": "^3.0.4" } }, "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg=="],
|
"file-entry-cache": ["file-entry-cache@6.0.1", "", { "dependencies": { "flat-cache": "^3.0.4" } }, "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg=="],
|
||||||
|
|
||||||
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, ""],
|
"file-stream-rotator": ["file-stream-rotator@0.6.1", "", { "dependencies": { "moment": "^2.29.1" } }, "sha512-u+dBid4PvZw17PmDeRcNOtCP9CCK/9lRN2w+r1xIS7yOL9JFrIBKTvrYsxT4P0pGtThYTn++QS5ChHaUov3+zQ=="],
|
||||||
|
|
||||||
|
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
|
||||||
|
|
||||||
"find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
|
"find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
|
||||||
|
|
||||||
@@ -242,19 +263,21 @@
|
|||||||
|
|
||||||
"flatted": ["flatted@3.3.2", "", {}, "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA=="],
|
"flatted": ["flatted@3.3.2", "", {}, "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA=="],
|
||||||
|
|
||||||
"form-data": ["form-data@4.0.1", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "mime-types": "^2.1.12" } }, ""],
|
"fn.name": ["fn.name@1.1.0", "", {}, "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="],
|
||||||
|
|
||||||
|
"form-data": ["form-data@4.0.1", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "mime-types": "^2.1.12" } }, "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw=="],
|
||||||
|
|
||||||
"formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="],
|
"formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="],
|
||||||
|
|
||||||
"formidable": ["formidable@2.1.2", "", { "dependencies": { "dezalgo": "^1.0.4", "hexoid": "^1.0.0", "once": "^1.4.0", "qs": "^6.11.0" } }, ""],
|
"formidable": ["formidable@2.1.2", "", { "dependencies": { "dezalgo": "^1.0.4", "hexoid": "^1.0.0", "once": "^1.4.0", "qs": "^6.11.0" } }, "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g=="],
|
||||||
|
|
||||||
"fs.realpath": ["fs.realpath@1.0.0", "", {}, ""],
|
"fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="],
|
||||||
|
|
||||||
"function-bind": ["function-bind@1.1.2", "", {}, ""],
|
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
|
||||||
|
|
||||||
"get-intrinsic": ["get-intrinsic@1.2.7", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "function-bind": "^1.1.2", "get-proto": "^1.0.0", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, ""],
|
"get-intrinsic": ["get-intrinsic@1.2.7", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "function-bind": "^1.1.2", "get-proto": "^1.0.0", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA=="],
|
||||||
|
|
||||||
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, ""],
|
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
|
||||||
|
|
||||||
"glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
|
"glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
|
||||||
|
|
||||||
@@ -264,49 +287,53 @@
|
|||||||
|
|
||||||
"globby": ["globby@11.1.0", "", { "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.2.9", "ignore": "^5.2.0", "merge2": "^1.4.1", "slash": "^3.0.0" } }, "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g=="],
|
"globby": ["globby@11.1.0", "", { "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.2.9", "ignore": "^5.2.0", "merge2": "^1.4.1", "slash": "^3.0.0" } }, "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g=="],
|
||||||
|
|
||||||
"gopd": ["gopd@1.2.0", "", {}, ""],
|
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
|
||||||
|
|
||||||
"graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="],
|
"graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="],
|
||||||
|
|
||||||
"has-flag": ["has-flag@4.0.0", "", {}, ""],
|
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
|
||||||
|
|
||||||
"has-symbols": ["has-symbols@1.1.0", "", {}, ""],
|
"has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
|
||||||
|
|
||||||
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, ""],
|
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
|
||||||
|
|
||||||
"helmet": ["helmet@7.2.0", "", {}, ""],
|
"helmet": ["helmet@7.2.0", "", {}, "sha512-ZRiwvN089JfMXokizgqEPXsl2Guk094yExfoDXR0cBYWxtBbaSww/w+vT4WEJsBW2iTUi1GgZ6swmoug3Oy4Xw=="],
|
||||||
|
|
||||||
"hexoid": ["hexoid@1.0.0", "", {}, ""],
|
"hexoid": ["hexoid@1.0.0", "", {}, "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g=="],
|
||||||
|
|
||||||
"hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="],
|
"hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="],
|
||||||
|
|
||||||
"htmlparser2": ["htmlparser2@8.0.2", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.0.1", "entities": "^4.4.0" } }, "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA=="],
|
"htmlparser2": ["htmlparser2@8.0.2", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.0.1", "entities": "^4.4.0" } }, "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA=="],
|
||||||
|
|
||||||
"husky": ["husky@9.1.7", "", { "bin": "bin.js" }, "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA=="],
|
"husky": ["husky@9.1.7", "", { "bin": { "husky": "bin.js" } }, "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA=="],
|
||||||
|
|
||||||
"ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
|
"ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
|
||||||
|
|
||||||
"import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="],
|
"import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="],
|
||||||
|
|
||||||
"imurmurhash": ["imurmurhash@0.1.4", "", {}, ""],
|
"imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
|
||||||
|
|
||||||
"inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, ""],
|
"inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="],
|
||||||
|
|
||||||
"inherits": ["inherits@2.0.4", "", {}, ""],
|
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
|
||||||
|
|
||||||
|
"is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="],
|
||||||
|
|
||||||
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
|
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
|
||||||
|
|
||||||
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
|
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
|
||||||
|
|
||||||
"is-number": ["is-number@7.0.0", "", {}, ""],
|
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
|
||||||
|
|
||||||
"is-path-inside": ["is-path-inside@3.0.3", "", {}, "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ=="],
|
"is-path-inside": ["is-path-inside@3.0.3", "", {}, "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ=="],
|
||||||
|
|
||||||
"is-plain-object": ["is-plain-object@5.0.0", "", {}, "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="],
|
"is-plain-object": ["is-plain-object@5.0.0", "", {}, "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="],
|
||||||
|
|
||||||
"isexe": ["isexe@2.0.0", "", {}, ""],
|
"is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="],
|
||||||
|
|
||||||
"js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": "bin/js-yaml.js" }, ""],
|
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||||
|
|
||||||
|
"js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
|
||||||
|
|
||||||
"json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="],
|
"json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="],
|
||||||
|
|
||||||
@@ -314,71 +341,81 @@
|
|||||||
|
|
||||||
"json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="],
|
"json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="],
|
||||||
|
|
||||||
"jsonwebtoken": ["jsonwebtoken@9.0.2", "", { "dependencies": { "jws": "^3.2.2", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", "lodash.isnumber": "^3.0.3", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.once": "^4.0.0", "ms": "^2.1.1", "semver": "^7.5.4" } }, ""],
|
"jsonwebtoken": ["jsonwebtoken@9.0.2", "", { "dependencies": { "jws": "^3.2.2", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", "lodash.isnumber": "^3.0.3", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.once": "^4.0.0", "ms": "^2.1.1", "semver": "^7.5.4" } }, "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ=="],
|
||||||
|
|
||||||
"jwa": ["jwa@1.4.1", "", { "dependencies": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, ""],
|
"jwa": ["jwa@1.4.1", "", { "dependencies": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA=="],
|
||||||
|
|
||||||
"jws": ["jws@3.2.2", "", { "dependencies": { "jwa": "^1.4.1", "safe-buffer": "^5.0.1" } }, ""],
|
"jws": ["jws@3.2.2", "", { "dependencies": { "jwa": "^1.4.1", "safe-buffer": "^5.0.1" } }, "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA=="],
|
||||||
|
|
||||||
"keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
|
"keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
|
||||||
|
|
||||||
|
"kuler": ["kuler@2.0.0", "", {}, "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="],
|
||||||
|
|
||||||
"levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
|
"levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
|
||||||
|
|
||||||
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
|
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
|
||||||
|
|
||||||
"lodash.includes": ["lodash.includes@4.3.0", "", {}, ""],
|
"lodash.includes": ["lodash.includes@4.3.0", "", {}, "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w=="],
|
||||||
|
|
||||||
"lodash.isboolean": ["lodash.isboolean@3.0.3", "", {}, ""],
|
"lodash.isboolean": ["lodash.isboolean@3.0.3", "", {}, "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="],
|
||||||
|
|
||||||
"lodash.isinteger": ["lodash.isinteger@4.0.4", "", {}, ""],
|
"lodash.isinteger": ["lodash.isinteger@4.0.4", "", {}, "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA=="],
|
||||||
|
|
||||||
"lodash.isnumber": ["lodash.isnumber@3.0.3", "", {}, ""],
|
"lodash.isnumber": ["lodash.isnumber@3.0.3", "", {}, "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw=="],
|
||||||
|
|
||||||
"lodash.isplainobject": ["lodash.isplainobject@4.0.6", "", {}, ""],
|
"lodash.isplainobject": ["lodash.isplainobject@4.0.6", "", {}, "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="],
|
||||||
|
|
||||||
"lodash.isstring": ["lodash.isstring@4.0.1", "", {}, ""],
|
"lodash.isstring": ["lodash.isstring@4.0.1", "", {}, "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="],
|
||||||
|
|
||||||
"lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="],
|
"lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="],
|
||||||
|
|
||||||
"lodash.once": ["lodash.once@4.1.1", "", {}, ""],
|
"lodash.once": ["lodash.once@4.1.1", "", {}, "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="],
|
||||||
|
|
||||||
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, ""],
|
"logform": ["logform@2.7.0", "", { "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", "fecha": "^4.2.0", "ms": "^2.1.1", "safe-stable-stringify": "^2.3.1", "triple-beam": "^1.3.0" } }, "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ=="],
|
||||||
|
|
||||||
|
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
||||||
|
|
||||||
"memoirist": ["memoirist@0.3.0", "", {}, "sha512-wR+4chMgVPq+T6OOsk40u9Wlpw1Pjx66NMNiYxCQQ4EUJ7jDs3D9kTCeKdBOkvAiqXlHLVJlvYL01PvIJ1MPNg=="],
|
"memoirist": ["memoirist@0.3.0", "", {}, "sha512-wR+4chMgVPq+T6OOsk40u9Wlpw1Pjx66NMNiYxCQQ4EUJ7jDs3D9kTCeKdBOkvAiqXlHLVJlvYL01PvIJ1MPNg=="],
|
||||||
|
|
||||||
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
|
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
|
||||||
|
|
||||||
"methods": ["methods@1.1.2", "", {}, ""],
|
"methods": ["methods@1.1.2", "", {}, "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="],
|
||||||
|
|
||||||
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, ""],
|
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
|
||||||
|
|
||||||
"mime": ["mime@2.6.0", "", { "bin": "cli.js" }, ""],
|
"mime": ["mime@2.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg=="],
|
||||||
|
|
||||||
"mime-db": ["mime-db@1.52.0", "", {}, ""],
|
"mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
|
||||||
|
|
||||||
"mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, ""],
|
"mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
|
||||||
|
|
||||||
"minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
|
"minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
|
||||||
|
|
||||||
"ms": ["ms@2.1.3", "", {}, ""],
|
"moment": ["moment@2.30.1", "", {}, "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how=="],
|
||||||
|
|
||||||
"nanoid": ["nanoid@3.3.8", "", { "bin": "bin/nanoid.cjs" }, "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="],
|
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||||
|
|
||||||
"natural-compare": ["natural-compare@1.4.0", "", {}, ""],
|
"nanoid": ["nanoid@3.3.8", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="],
|
||||||
|
|
||||||
|
"natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
|
||||||
|
|
||||||
"node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="],
|
"node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="],
|
||||||
|
|
||||||
"node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="],
|
"node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="],
|
||||||
|
|
||||||
"object-inspect": ["object-inspect@1.13.3", "", {}, ""],
|
"object-hash": ["object-hash@3.0.0", "", {}, "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw=="],
|
||||||
|
|
||||||
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, ""],
|
"object-inspect": ["object-inspect@1.13.3", "", {}, "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA=="],
|
||||||
|
|
||||||
|
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
|
||||||
|
|
||||||
|
"one-time": ["one-time@1.0.0", "", { "dependencies": { "fn.name": "1.x.x" } }, "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g=="],
|
||||||
|
|
||||||
"openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
|
"openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
|
||||||
|
|
||||||
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
|
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
|
||||||
|
|
||||||
"p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, ""],
|
"p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
|
||||||
|
|
||||||
"p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="],
|
"p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="],
|
||||||
|
|
||||||
@@ -386,79 +423,93 @@
|
|||||||
|
|
||||||
"parse-srcset": ["parse-srcset@1.0.2", "", {}, "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q=="],
|
"parse-srcset": ["parse-srcset@1.0.2", "", {}, "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q=="],
|
||||||
|
|
||||||
"path-exists": ["path-exists@4.0.0", "", {}, ""],
|
"path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
|
||||||
|
|
||||||
"path-is-absolute": ["path-is-absolute@1.0.1", "", {}, ""],
|
"path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="],
|
||||||
|
|
||||||
"path-key": ["path-key@3.1.1", "", {}, ""],
|
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
||||||
|
|
||||||
"path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="],
|
"path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="],
|
||||||
|
|
||||||
"pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="],
|
"pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="],
|
||||||
|
|
||||||
"picocolors": ["picocolors@1.1.1", "", {}, ""],
|
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
||||||
|
|
||||||
"picomatch": ["picomatch@2.3.1", "", {}, ""],
|
"picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||||
|
|
||||||
"postcss": ["postcss@8.5.1", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ=="],
|
"postcss": ["postcss@8.5.1", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ=="],
|
||||||
|
|
||||||
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
|
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
|
||||||
|
|
||||||
"prettier": ["prettier@3.4.2", "", { "bin": "bin/prettier.cjs" }, "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ=="],
|
"prettier": ["prettier@3.4.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ=="],
|
||||||
|
|
||||||
"prettier-linter-helpers": ["prettier-linter-helpers@1.0.0", "", { "dependencies": { "fast-diff": "^1.1.2" } }, "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w=="],
|
"prettier-linter-helpers": ["prettier-linter-helpers@1.0.0", "", { "dependencies": { "fast-diff": "^1.1.2" } }, "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w=="],
|
||||||
|
|
||||||
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
|
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
|
||||||
|
|
||||||
"qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, ""],
|
"qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="],
|
||||||
|
|
||||||
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
|
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
|
||||||
|
|
||||||
|
"readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
|
||||||
|
|
||||||
"resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
|
"resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
|
||||||
|
|
||||||
"reusify": ["reusify@1.0.4", "", {}, "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="],
|
"reusify": ["reusify@1.0.4", "", {}, "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="],
|
||||||
|
|
||||||
"rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": "bin.js" }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="],
|
"rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="],
|
||||||
|
|
||||||
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
|
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
|
||||||
|
|
||||||
"safe-buffer": ["safe-buffer@5.2.1", "", {}, ""],
|
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
||||||
|
|
||||||
|
"safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="],
|
||||||
|
|
||||||
"sanitize-html": ["sanitize-html@2.14.0", "", { "dependencies": { "deepmerge": "^4.2.2", "escape-string-regexp": "^4.0.0", "htmlparser2": "^8.0.0", "is-plain-object": "^5.0.0", "parse-srcset": "^1.0.2", "postcss": "^8.3.11" } }, "sha512-CafX+IUPxZshXqqRaG9ZClSlfPVjSxI0td7n07hk8QO2oO+9JDnlcL8iM8TWeOXOIBFgIOx6zioTzM53AOMn3g=="],
|
"sanitize-html": ["sanitize-html@2.14.0", "", { "dependencies": { "deepmerge": "^4.2.2", "escape-string-regexp": "^4.0.0", "htmlparser2": "^8.0.0", "is-plain-object": "^5.0.0", "parse-srcset": "^1.0.2", "postcss": "^8.3.11" } }, "sha512-CafX+IUPxZshXqqRaG9ZClSlfPVjSxI0td7n07hk8QO2oO+9JDnlcL8iM8TWeOXOIBFgIOx6zioTzM53AOMn3g=="],
|
||||||
|
|
||||||
"semver": ["semver@7.7.0", "", { "bin": "bin/semver.js" }, "sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ=="],
|
"semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
|
||||||
|
|
||||||
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, ""],
|
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
||||||
|
|
||||||
"shebang-regex": ["shebang-regex@3.0.0", "", {}, ""],
|
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
||||||
|
|
||||||
"side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, ""],
|
"side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="],
|
||||||
|
|
||||||
"side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, ""],
|
"side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="],
|
||||||
|
|
||||||
"side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, ""],
|
"side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="],
|
||||||
|
|
||||||
"side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, ""],
|
"side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="],
|
||||||
|
|
||||||
"slash": ["slash@3.0.0", "", {}, ""],
|
"simple-swizzle": ["simple-swizzle@0.2.2", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg=="],
|
||||||
|
|
||||||
|
"slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
|
||||||
|
|
||||||
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
||||||
|
|
||||||
"strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, ""],
|
"stack-trace": ["stack-trace@0.0.10", "", {}, "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg=="],
|
||||||
|
|
||||||
"strip-json-comments": ["strip-json-comments@3.1.1", "", {}, ""],
|
"string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="],
|
||||||
|
|
||||||
"superagent": ["superagent@8.1.2", "", { "dependencies": { "component-emitter": "^1.3.0", "cookiejar": "^2.1.4", "debug": "^4.3.4", "fast-safe-stringify": "^2.1.1", "form-data": "^4.0.0", "formidable": "^2.1.2", "methods": "^1.1.2", "mime": "2.6.0", "qs": "^6.11.0", "semver": "^7.3.8" } }, ""],
|
"strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||||
|
|
||||||
"supertest": ["supertest@6.3.4", "", { "dependencies": { "methods": "^1.1.2", "superagent": "^8.1.2" } }, ""],
|
"strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
|
||||||
|
|
||||||
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, ""],
|
"superagent": ["superagent@8.1.2", "", { "dependencies": { "component-emitter": "^1.3.0", "cookiejar": "^2.1.4", "debug": "^4.3.4", "fast-safe-stringify": "^2.1.1", "form-data": "^4.0.0", "formidable": "^2.1.2", "methods": "^1.1.2", "mime": "2.6.0", "qs": "^6.11.0", "semver": "^7.3.8" } }, "sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA=="],
|
||||||
|
|
||||||
|
"supertest": ["supertest@6.3.4", "", { "dependencies": { "methods": "^1.1.2", "superagent": "^8.1.2" } }, "sha512-erY3HFDG0dPnhw4U+udPfrzXa4xhSG+n4rxfRuZWCUvjFWwKl+OxWf/7zk50s84/fAAs7vf5QAb9uRa0cCykxw=="],
|
||||||
|
|
||||||
|
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
|
||||||
|
|
||||||
"synckit": ["synckit@0.9.2", "", { "dependencies": { "@pkgr/core": "^0.1.0", "tslib": "^2.6.2" } }, "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw=="],
|
"synckit": ["synckit@0.9.2", "", { "dependencies": { "@pkgr/core": "^0.1.0", "tslib": "^2.6.2" } }, "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw=="],
|
||||||
|
|
||||||
|
"text-hex": ["text-hex@1.0.0", "", {}, "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="],
|
||||||
|
|
||||||
"text-table": ["text-table@0.2.0", "", {}, "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw=="],
|
"text-table": ["text-table@0.2.0", "", {}, "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw=="],
|
||||||
|
|
||||||
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, ""],
|
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
||||||
|
|
||||||
|
"triple-beam": ["triple-beam@1.4.1", "", {}, "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg=="],
|
||||||
|
|
||||||
"ts-api-utils": ["ts-api-utils@1.4.3", "", { "peerDependencies": { "typescript": ">=4.2.0" } }, "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw=="],
|
"ts-api-utils": ["ts-api-utils@1.4.3", "", { "peerDependencies": { "typescript": ">=4.2.0" } }, "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw=="],
|
||||||
|
|
||||||
@@ -468,60 +519,52 @@
|
|||||||
|
|
||||||
"type-fest": ["type-fest@0.20.2", "", {}, "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ=="],
|
"type-fest": ["type-fest@0.20.2", "", {}, "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ=="],
|
||||||
|
|
||||||
"typescript": ["typescript@5.7.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, ""],
|
"typescript": ["typescript@5.7.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw=="],
|
||||||
|
|
||||||
"undici-types": ["undici-types@6.19.8", "", {}, ""],
|
"undici-types": ["undici-types@6.19.8", "", {}, "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="],
|
||||||
|
|
||||||
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
|
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
|
||||||
|
|
||||||
"uuid": ["uuid@11.0.5", "", { "bin": "dist/esm/bin/uuid" }, "sha512-508e6IcKLrhxKdBbcA2b4KQZlLVp2+J5UwQ6F7Drckkc5N9ZJwFa4TgWtsww9UG8fGHbm6gbV19TdM5pQ4GaIA=="],
|
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
|
||||||
|
|
||||||
|
"uuid": ["uuid@11.0.5", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-508e6IcKLrhxKdBbcA2b4KQZlLVp2+J5UwQ6F7Drckkc5N9ZJwFa4TgWtsww9UG8fGHbm6gbV19TdM5pQ4GaIA=="],
|
||||||
|
|
||||||
"web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="],
|
"web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="],
|
||||||
|
|
||||||
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "bin/node-which" } }, ""],
|
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||||
|
|
||||||
|
"winston": ["winston@3.17.0", "", { "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.2", "async": "^3.2.3", "is-stream": "^2.0.0", "logform": "^2.7.0", "one-time": "^1.0.0", "readable-stream": "^3.4.0", "safe-stable-stringify": "^2.3.1", "stack-trace": "0.0.x", "triple-beam": "^1.3.0", "winston-transport": "^4.9.0" } }, "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw=="],
|
||||||
|
|
||||||
|
"winston-daily-rotate-file": ["winston-daily-rotate-file@5.0.0", "", { "dependencies": { "file-stream-rotator": "^0.6.1", "object-hash": "^3.0.0", "triple-beam": "^1.4.1", "winston-transport": "^4.7.0" }, "peerDependencies": { "winston": "^3" } }, "sha512-JDjiXXkM5qvwY06733vf09I2wnMXpZEhxEVOSPenZMii+g7pcDcTBt2MRugnoi8BwVSuCT2jfRXBUy+n1Zz/Yw=="],
|
||||||
|
|
||||||
|
"winston-transport": ["winston-transport@4.9.0", "", { "dependencies": { "logform": "^2.7.0", "readable-stream": "^3.6.2", "triple-beam": "^1.3.0" } }, "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A=="],
|
||||||
|
|
||||||
"word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="],
|
"word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="],
|
||||||
|
|
||||||
"wrappy": ["wrappy@1.0.2", "", {}, ""],
|
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
|
||||||
|
|
||||||
"ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, ""],
|
"ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="],
|
||||||
|
|
||||||
"yocto-queue": ["yocto-queue@0.1.0", "", {}, ""],
|
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
|
||||||
|
|
||||||
"zhead": ["zhead@2.2.4", "", {}, "sha512-8F0OI5dpWIA5IGG5NHUg9staDwz/ZPxZtvGVf01j7vHqSyZ0raHY+78atOVxRqb73AotX22uV1pXt3gYSstGag=="],
|
"zhead": ["zhead@2.2.4", "", {}, "sha512-8F0OI5dpWIA5IGG5NHUg9staDwz/ZPxZtvGVf01j7vHqSyZ0raHY+78atOVxRqb73AotX22uV1pXt3gYSstGag=="],
|
||||||
|
|
||||||
"zod": ["zod@3.24.1", "", {}, ""],
|
"zod": ["zod@3.24.1", "", {}, "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A=="],
|
||||||
|
|
||||||
"@eslint/eslintrc/ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
|
|
||||||
|
|
||||||
"@eslint/eslintrc/globals": ["globals@13.24.0", "", { "dependencies": { "type-fest": "^0.20.2" } }, "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ=="],
|
|
||||||
|
|
||||||
"@eslint/eslintrc/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
|
|
||||||
|
|
||||||
"@humanwhocodes/config-array/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
|
|
||||||
|
|
||||||
"@scalar/themes/@scalar/types": ["@scalar/types@0.0.30", "", { "dependencies": { "@scalar/openapi-types": "0.1.7", "@unhead/schema": "^1.11.11" } }, "sha512-rhgwovQb5f7PXuUB5bLUElpo90fdsiwcOgBXVWZ6n6dnFSKovNJ7GPXQimsZioMzTF6TdwfP94UpZVdZAK4aTw=="],
|
"@scalar/themes/@scalar/types": ["@scalar/types@0.0.30", "", { "dependencies": { "@scalar/openapi-types": "0.1.7", "@unhead/schema": "^1.11.11" } }, "sha512-rhgwovQb5f7PXuUB5bLUElpo90fdsiwcOgBXVWZ6n6dnFSKovNJ7GPXQimsZioMzTF6TdwfP94UpZVdZAK4aTw=="],
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
|
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
|
||||||
|
|
||||||
|
"color/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="],
|
||||||
|
|
||||||
|
"color-string/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],
|
||||||
|
|
||||||
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||||
|
|
||||||
"glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
|
|
||||||
|
|
||||||
"sanitize-html/escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
|
|
||||||
|
|
||||||
"@eslint/eslintrc/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
|
|
||||||
|
|
||||||
"@eslint/eslintrc/globals/type-fest": ["type-fest@0.20.2", "", {}, "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ=="],
|
|
||||||
|
|
||||||
"@eslint/eslintrc/minimatch/brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="],
|
|
||||||
|
|
||||||
"@humanwhocodes/config-array/minimatch/brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="],
|
|
||||||
|
|
||||||
"@scalar/themes/@scalar/types/@scalar/openapi-types": ["@scalar/openapi-types@0.1.7", "", {}, "sha512-oOTG3JQifg55U3DhKB7WdNIxFnJzbPJe7rqdyWdio977l8IkxQTVmObftJhdNIMvhV2K+1f/bDoMQGu6yTaD0A=="],
|
"@scalar/themes/@scalar/types/@scalar/openapi-types": ["@scalar/openapi-types@0.1.7", "", {}, "sha512-oOTG3JQifg55U3DhKB7WdNIxFnJzbPJe7rqdyWdio977l8IkxQTVmObftJhdNIMvhV2K+1f/bDoMQGu6yTaD0A=="],
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
|
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
|
||||||
|
|
||||||
"glob/minimatch/brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="],
|
"color/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,10 @@ RUN python -m venv /opt/venv
|
|||||||
ENV PATH="/opt/venv/bin:$PATH"
|
ENV PATH="/opt/venv/bin:$PATH"
|
||||||
|
|
||||||
# Install Python dependencies with specific versions and CPU-only variants
|
# Install Python dependencies with specific versions and CPU-only variants
|
||||||
RUN pip install --no-cache-dir torch==2.1.2 torchaudio==2.1.2 --index-url https://download.pytorch.org/whl/cpu
|
RUN pip install --no-cache-dir "numpy>=1.24.3,<2.0.0" && \
|
||||||
RUN pip install --no-cache-dir faster-whisper==0.10.0 openwakeword==0.4.0 pyaudio==0.2.14 sounddevice==0.4.6
|
pip install --no-cache-dir torch==2.1.2 torchaudio==2.1.2 --index-url https://download.pytorch.org/whl/cpu && \
|
||||||
|
pip install --no-cache-dir faster-whisper==0.10.0 openwakeword==0.4.0 pyaudio==0.2.14 sounddevice==0.4.6 requests==2.31.0 && \
|
||||||
|
pip freeze > /opt/venv/requirements.txt
|
||||||
|
|
||||||
# Create final image
|
# Create final image
|
||||||
FROM python:3.10-slim
|
FROM python:3.10-slim
|
||||||
@@ -23,10 +25,14 @@ FROM python:3.10-slim
|
|||||||
COPY --from=builder /opt/venv /opt/venv
|
COPY --from=builder /opt/venv /opt/venv
|
||||||
ENV PATH="/opt/venv/bin:$PATH"
|
ENV PATH="/opt/venv/bin:$PATH"
|
||||||
|
|
||||||
# Install only runtime dependencies
|
# Install audio dependencies
|
||||||
RUN apt-get update && apt-get install -y \
|
RUN apt-get update && apt-get install -y \
|
||||||
portaudio19-dev \
|
portaudio19-dev \
|
||||||
python3-pyaudio \
|
python3-pyaudio \
|
||||||
|
alsa-utils \
|
||||||
|
libasound2 \
|
||||||
|
libasound2-plugins \
|
||||||
|
pulseaudio \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Create necessary directories
|
# Create necessary directories
|
||||||
@@ -54,5 +60,9 @@ ENV PYTHONMALLOC=malloc \
|
|||||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||||
CMD ps aux | grep '[p]ython' || exit 1
|
CMD ps aux | grep '[p]ython' || exit 1
|
||||||
|
|
||||||
# Run the wake word detection service with resource constraints
|
# Copy audio setup script
|
||||||
CMD ["python", "-X", "faulthandler", "wake_word_detector.py"]
|
COPY setup-audio.sh /setup-audio.sh
|
||||||
|
RUN chmod +x /setup-audio.sh
|
||||||
|
|
||||||
|
# Start command
|
||||||
|
CMD ["/bin/bash", "-c", "/setup-audio.sh && python -u wake_word_detector.py"]
|
||||||
16
docker/speech/setup-audio.sh
Executable file
16
docker/speech/setup-audio.sh
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Wait for PulseAudio to be ready
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
# Mute the monitor to prevent feedback
|
||||||
|
pactl set-source-mute alsa_output.pci-0000_00_1b.0.analog-stereo.monitor 1
|
||||||
|
|
||||||
|
# Set microphone sensitivity to 65%
|
||||||
|
pactl set-source-volume alsa_input.pci-0000_00_1b.0.analog-stereo 65%
|
||||||
|
|
||||||
|
# Set speaker volume to 40%
|
||||||
|
pactl set-sink-volume alsa_output.pci-0000_00_1b.0.analog-stereo 40%
|
||||||
|
|
||||||
|
# Make the script executable
|
||||||
|
chmod +x /setup-audio.sh
|
||||||
@@ -8,46 +8,274 @@ from openwakeword import Model
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import wave
|
import wave
|
||||||
from faster_whisper import WhisperModel
|
from faster_whisper import WhisperModel
|
||||||
|
import requests
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
|
||||||
|
# Set up logging
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.DEBUG,
|
||||||
|
format='%(asctime)s - %(levelname)s - %(message)s'
|
||||||
|
)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
SAMPLE_RATE = 16000
|
SAMPLE_RATE = 16000
|
||||||
CHANNELS = 1
|
CHANNELS = 1
|
||||||
CHUNK_SIZE = 1024
|
CHUNK_SIZE = 1024
|
||||||
BUFFER_DURATION = 30 # seconds to keep in buffer
|
BUFFER_DURATION = 10 # seconds to keep in buffer
|
||||||
DETECTION_THRESHOLD = 0.5
|
DETECTION_THRESHOLD = 0.5
|
||||||
|
CONTINUOUS_TRANSCRIPTION_INTERVAL = 3 # seconds between transcriptions
|
||||||
|
MAX_MODEL_LOAD_RETRIES = 3
|
||||||
|
MODEL_LOAD_RETRY_DELAY = 5 # seconds
|
||||||
|
MODEL_DOWNLOAD_TIMEOUT = 600 # 10 minutes timeout for model download
|
||||||
|
|
||||||
# Wake word models to use
|
# Audio processing parameters
|
||||||
WAKE_WORDS = ["hey_jarvis", "ok_google", "alexa"]
|
NOISE_THRESHOLD = 0.08 # Increased threshold for better noise filtering
|
||||||
|
MIN_SPEECH_DURATION = 2.0 # Longer minimum duration to avoid fragments
|
||||||
|
SILENCE_DURATION = 1.0 # Longer silence duration
|
||||||
|
MAX_REPETITIONS = 1 # More aggressive repetition filtering
|
||||||
|
ECHO_THRESHOLD = 0.75 # More sensitive echo detection
|
||||||
|
MIN_SEGMENT_DURATION = 1.0 # Longer minimum segment duration
|
||||||
|
FEEDBACK_WINDOW = 5 # Window size for feedback detection in seconds
|
||||||
|
|
||||||
# Initialize the ASR model
|
# Feature flags from environment
|
||||||
asr_model = WhisperModel(
|
WAKE_WORD_ENABLED = os.environ.get('ENABLE_WAKE_WORD', 'false').lower() == 'true'
|
||||||
model_size_or_path=os.environ.get('ASR_MODEL', 'base.en'),
|
SPEECH_ENABLED = os.environ.get('ENABLE_SPEECH_FEATURES', 'true').lower() == 'true'
|
||||||
device="cpu",
|
|
||||||
compute_type="int8",
|
# Wake word models to use (only if wake word is enabled)
|
||||||
download_root=os.environ.get('ASR_MODEL_PATH', '/models')
|
WAKE_WORDS = ["alexa"] # Using 'alexa' as temporary replacement for 'gaja'
|
||||||
)
|
WAKE_WORD_ALIAS = "gaja" # What we print when wake word is detected
|
||||||
|
|
||||||
|
# Home Assistant Configuration
|
||||||
|
HASS_HOST = os.environ.get('HASS_HOST', 'http://homeassistant.local:8123')
|
||||||
|
HASS_TOKEN = os.environ.get('HASS_TOKEN')
|
||||||
|
|
||||||
|
def initialize_asr_model():
|
||||||
|
"""Initialize the ASR model with retries and timeout"""
|
||||||
|
model_path = os.environ.get('ASR_MODEL_PATH', '/models')
|
||||||
|
model_name = os.environ.get('ASR_MODEL', 'large-v3')
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
for attempt in range(MAX_MODEL_LOAD_RETRIES):
|
||||||
|
try:
|
||||||
|
if time.time() - start_time > MODEL_DOWNLOAD_TIMEOUT:
|
||||||
|
logger.error("Model download timeout exceeded")
|
||||||
|
raise TimeoutError("Model download took too long")
|
||||||
|
|
||||||
|
logger.info(f"Loading ASR model (attempt {attempt + 1}/{MAX_MODEL_LOAD_RETRIES})")
|
||||||
|
model = WhisperModel(
|
||||||
|
model_size_or_path=model_name,
|
||||||
|
device="cpu",
|
||||||
|
compute_type="int8",
|
||||||
|
download_root=model_path,
|
||||||
|
num_workers=1 # Reduce concurrent downloads
|
||||||
|
)
|
||||||
|
logger.info("ASR model loaded successfully")
|
||||||
|
return model
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to load ASR model (attempt {attempt + 1}): {e}")
|
||||||
|
if attempt < MAX_MODEL_LOAD_RETRIES - 1:
|
||||||
|
logger.info(f"Retrying in {MODEL_LOAD_RETRY_DELAY} seconds...")
|
||||||
|
time.sleep(MODEL_LOAD_RETRY_DELAY)
|
||||||
|
else:
|
||||||
|
logger.error("Failed to load ASR model after all retries")
|
||||||
|
raise
|
||||||
|
|
||||||
|
# Initialize the ASR model with retries
|
||||||
|
try:
|
||||||
|
asr_model = initialize_asr_model()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Critical error initializing ASR model: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
def send_command_to_hass(domain, service, entity_id):
|
||||||
|
"""Send command to Home Assistant"""
|
||||||
|
if not HASS_TOKEN:
|
||||||
|
logger.error("Error: HASS_TOKEN not set")
|
||||||
|
return False
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"Bearer {HASS_TOKEN}",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
|
||||||
|
url = f"{HASS_HOST}/api/services/{domain}/{service}"
|
||||||
|
data = {"entity_id": entity_id}
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.post(url, headers=headers, json=data)
|
||||||
|
response.raise_for_status()
|
||||||
|
logger.info(f"Command sent: {domain}.{service} for {entity_id}")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error sending command to Home Assistant: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def is_speech(audio_data, threshold=NOISE_THRESHOLD):
|
||||||
|
"""Detect if audio segment contains speech based on amplitude and frequency content"""
|
||||||
|
# Calculate RMS amplitude
|
||||||
|
rms = np.sqrt(np.mean(np.square(audio_data)))
|
||||||
|
|
||||||
|
# Calculate signal energy in speech frequency range (100-4000 Hz)
|
||||||
|
fft = np.fft.fft(audio_data)
|
||||||
|
freqs = np.fft.fftfreq(len(audio_data), 1/SAMPLE_RATE)
|
||||||
|
speech_mask = (np.abs(freqs) >= 100) & (np.abs(freqs) <= 4000)
|
||||||
|
speech_energy = np.sum(np.abs(fft[speech_mask])) / len(audio_data)
|
||||||
|
|
||||||
|
# Enhanced echo detection
|
||||||
|
# 1. Check for periodic patterns in the signal
|
||||||
|
autocorr = np.correlate(audio_data, audio_data, mode='full')
|
||||||
|
autocorr = autocorr[len(autocorr)//2:] # Use only positive lags
|
||||||
|
peaks = np.where(autocorr > ECHO_THRESHOLD * np.max(autocorr))[0]
|
||||||
|
peak_spacing = np.diff(peaks)
|
||||||
|
has_periodic_echo = len(peak_spacing) > 2 and np.std(peak_spacing) < 0.1 * np.mean(peak_spacing)
|
||||||
|
|
||||||
|
# 2. Check for sudden amplitude changes
|
||||||
|
amplitude_envelope = np.abs(audio_data)
|
||||||
|
amplitude_changes = np.diff(amplitude_envelope)
|
||||||
|
has_feedback_spikes = np.any(np.abs(amplitude_changes) > threshold * 2)
|
||||||
|
|
||||||
|
# 3. Check frequency distribution
|
||||||
|
freq_magnitudes = np.abs(fft)[:len(fft)//2]
|
||||||
|
peak_freqs = freqs[:len(fft)//2][np.argsort(freq_magnitudes)[-3:]]
|
||||||
|
has_feedback_freqs = np.any((peak_freqs > 2000) & (peak_freqs < 4000))
|
||||||
|
|
||||||
|
# Combine all criteria
|
||||||
|
is_valid_speech = (
|
||||||
|
rms > threshold and
|
||||||
|
speech_energy > threshold and
|
||||||
|
not has_periodic_echo and
|
||||||
|
not has_feedback_spikes and
|
||||||
|
not has_feedback_freqs
|
||||||
|
)
|
||||||
|
|
||||||
|
return is_valid_speech
|
||||||
|
|
||||||
|
def process_command(text):
|
||||||
|
"""Process the transcribed command and execute appropriate action"""
|
||||||
|
text = text.lower().strip()
|
||||||
|
|
||||||
|
# Skip if text is too short or contains numbers (likely noise)
|
||||||
|
if len(text) < 5 or any(char.isdigit() for char in text):
|
||||||
|
logger.debug("Text too short or contains numbers, skipping")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Enhanced noise pattern detection
|
||||||
|
noise_patterns = ["lei", "los", "und", "aber", "nicht mehr", "das das", "und und"]
|
||||||
|
for pattern in noise_patterns:
|
||||||
|
if text.count(pattern) > 1: # More aggressive pattern filtering
|
||||||
|
logger.debug(f"Detected noise pattern '{pattern}', skipping")
|
||||||
|
return
|
||||||
|
|
||||||
|
# More aggressive repetition detection
|
||||||
|
words = text.split()
|
||||||
|
if len(words) >= 2:
|
||||||
|
# Check for immediate word repetitions
|
||||||
|
for i in range(len(words)-1):
|
||||||
|
if words[i] == words[i+1]:
|
||||||
|
logger.debug(f"Detected immediate word repetition: '{words[i]}', skipping")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check for phrase repetitions
|
||||||
|
phrases = [' '.join(words[i:i+2]) for i in range(len(words)-1)]
|
||||||
|
phrase_counts = {}
|
||||||
|
for phrase in phrases:
|
||||||
|
phrase_counts[phrase] = phrase_counts.get(phrase, 0) + 1
|
||||||
|
if phrase_counts[phrase] > MAX_REPETITIONS:
|
||||||
|
logger.debug(f"Skipping due to excessive repetition: '{phrase}'")
|
||||||
|
return
|
||||||
|
|
||||||
|
# German command mappings
|
||||||
|
commands = {
|
||||||
|
"ausschalten": "turn_off",
|
||||||
|
"einschalten": "turn_on",
|
||||||
|
"an": "turn_on",
|
||||||
|
"aus": "turn_off"
|
||||||
|
}
|
||||||
|
|
||||||
|
rooms = {
|
||||||
|
"wohnzimmer": "living_room",
|
||||||
|
"küche": "kitchen",
|
||||||
|
"schlafzimmer": "bedroom",
|
||||||
|
"bad": "bathroom"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Detect room
|
||||||
|
detected_room = None
|
||||||
|
for german_room, english_room in rooms.items():
|
||||||
|
if german_room in text:
|
||||||
|
detected_room = english_room
|
||||||
|
break
|
||||||
|
|
||||||
|
# Detect command
|
||||||
|
detected_command = None
|
||||||
|
for german_cmd, english_cmd in commands.items():
|
||||||
|
if german_cmd in text:
|
||||||
|
detected_command = english_cmd
|
||||||
|
break
|
||||||
|
|
||||||
|
if detected_room and detected_command:
|
||||||
|
# Construct entity ID (assuming light)
|
||||||
|
entity_id = f"light.{detected_room}"
|
||||||
|
|
||||||
|
# Send command to Home Assistant
|
||||||
|
if send_command_to_hass("light", detected_command, entity_id):
|
||||||
|
logger.info(f"Executed: {detected_command} for {entity_id}")
|
||||||
|
else:
|
||||||
|
logger.error("Failed to execute command")
|
||||||
|
else:
|
||||||
|
logger.debug(f"No command found in text: '{text}'")
|
||||||
|
|
||||||
class AudioProcessor:
|
class AudioProcessor:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# Initialize wake word detection model
|
logger.info("Initializing AudioProcessor...")
|
||||||
self.wake_word_model = Model(
|
|
||||||
custom_model_paths=None, # Use default models
|
|
||||||
inference_framework="onnx" # Use ONNX for better performance
|
|
||||||
)
|
|
||||||
|
|
||||||
# Pre-load the wake word models
|
|
||||||
for wake_word in WAKE_WORDS:
|
|
||||||
self.wake_word_model.add_model(wake_word)
|
|
||||||
|
|
||||||
self.audio_buffer = queue.Queue()
|
self.audio_buffer = queue.Queue()
|
||||||
self.recording = False
|
self.recording = False
|
||||||
self.buffer = np.zeros(SAMPLE_RATE * BUFFER_DURATION)
|
self.buffer = np.zeros(SAMPLE_RATE * BUFFER_DURATION)
|
||||||
self.buffer_lock = threading.Lock()
|
self.buffer_lock = threading.Lock()
|
||||||
|
self.last_transcription_time = 0
|
||||||
|
self.stream = None
|
||||||
|
self.speech_detected = False
|
||||||
|
self.silence_frames = 0
|
||||||
|
self.speech_frames = 0
|
||||||
|
|
||||||
|
# Initialize wake word detection only if enabled
|
||||||
|
if WAKE_WORD_ENABLED:
|
||||||
|
try:
|
||||||
|
logger.info("Initializing wake word model...")
|
||||||
|
self.wake_word_model = Model(vad_threshold=0.5)
|
||||||
|
self.last_prediction = None
|
||||||
|
logger.info("Wake word model initialized successfully")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to initialize wake word model: {e}")
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
self.wake_word_model = None
|
||||||
|
self.last_prediction = None
|
||||||
|
logger.info("Wake word detection disabled")
|
||||||
|
|
||||||
|
def should_transcribe(self):
|
||||||
|
"""Determine if we should transcribe based on mode and timing"""
|
||||||
|
current_time = datetime.now().timestamp()
|
||||||
|
if not WAKE_WORD_ENABLED:
|
||||||
|
# Check if enough time has passed since last transcription
|
||||||
|
time_since_last = current_time - self.last_transcription_time
|
||||||
|
if time_since_last >= CONTINUOUS_TRANSCRIPTION_INTERVAL:
|
||||||
|
# Only transcribe if we detect speech
|
||||||
|
frames_per_chunk = CHUNK_SIZE
|
||||||
|
min_speech_frames = int(MIN_SPEECH_DURATION * SAMPLE_RATE / frames_per_chunk)
|
||||||
|
|
||||||
|
if self.speech_frames >= min_speech_frames:
|
||||||
|
self.last_transcription_time = current_time
|
||||||
|
self.speech_frames = 0 # Reset counter
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def audio_callback(self, indata, frames, time, status):
|
def audio_callback(self, indata, frames, time, status):
|
||||||
"""Callback for audio input"""
|
"""Callback for audio input"""
|
||||||
if status:
|
if status:
|
||||||
print(f"Audio callback status: {status}")
|
logger.warning(f"Audio callback status: {status}")
|
||||||
|
|
||||||
# Convert to mono if necessary
|
# Convert to mono if necessary
|
||||||
if CHANNELS > 1:
|
if CHANNELS > 1:
|
||||||
@@ -55,25 +283,45 @@ class AudioProcessor:
|
|||||||
else:
|
else:
|
||||||
audio_data = indata.flatten()
|
audio_data = indata.flatten()
|
||||||
|
|
||||||
|
# Check for speech
|
||||||
|
if is_speech(audio_data):
|
||||||
|
self.speech_frames += 1
|
||||||
|
self.silence_frames = 0
|
||||||
|
else:
|
||||||
|
self.silence_frames += 1
|
||||||
|
frames_per_chunk = CHUNK_SIZE
|
||||||
|
silence_frames_threshold = int(SILENCE_DURATION * SAMPLE_RATE / frames_per_chunk)
|
||||||
|
|
||||||
|
if self.silence_frames >= silence_frames_threshold:
|
||||||
|
self.speech_frames = 0
|
||||||
|
|
||||||
# Update circular buffer
|
# Update circular buffer
|
||||||
with self.buffer_lock:
|
with self.buffer_lock:
|
||||||
self.buffer = np.roll(self.buffer, -len(audio_data))
|
self.buffer = np.roll(self.buffer, -len(audio_data))
|
||||||
self.buffer[-len(audio_data):] = audio_data
|
self.buffer[-len(audio_data):] = audio_data
|
||||||
|
|
||||||
# Process for wake word detection
|
if WAKE_WORD_ENABLED:
|
||||||
prediction = self.wake_word_model.predict(audio_data)
|
# Process for wake word detection
|
||||||
|
self.last_prediction = self.wake_word_model.predict(audio_data)
|
||||||
|
|
||||||
# Check if wake word detected
|
# Check if wake word detected
|
||||||
for wake_word in WAKE_WORDS:
|
for wake_word in WAKE_WORDS:
|
||||||
if prediction[wake_word] > DETECTION_THRESHOLD:
|
confidence = self.last_prediction[wake_word]
|
||||||
print(f"Wake word detected: {wake_word} (confidence: {prediction[wake_word]:.2f})")
|
if confidence > DETECTION_THRESHOLD:
|
||||||
self.save_audio_segment(wake_word)
|
logger.info(
|
||||||
break
|
f"Wake word: {WAKE_WORD_ALIAS} (confidence: {confidence:.2f})"
|
||||||
|
)
|
||||||
|
self.process_audio()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# Continuous transcription mode
|
||||||
|
if self.should_transcribe():
|
||||||
|
self.process_audio()
|
||||||
|
|
||||||
def save_audio_segment(self, wake_word):
|
def process_audio(self):
|
||||||
"""Save the audio buffer when wake word is detected"""
|
"""Process the current audio buffer (save and transcribe)"""
|
||||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||||
filename = f"/audio/wake_word_{wake_word}_{timestamp}.wav"
|
filename = f"/audio/audio_segment_{timestamp}.wav"
|
||||||
|
|
||||||
# Save the audio buffer to a WAV file
|
# Save the audio buffer to a WAV file
|
||||||
with wave.open(filename, 'wb') as wf:
|
with wave.open(filename, 'wb') as wf:
|
||||||
@@ -85,89 +333,83 @@ class AudioProcessor:
|
|||||||
audio_data = (self.buffer * 32767).astype(np.int16)
|
audio_data = (self.buffer * 32767).astype(np.int16)
|
||||||
wf.writeframes(audio_data.tobytes())
|
wf.writeframes(audio_data.tobytes())
|
||||||
|
|
||||||
print(f"Saved audio segment to {filename}")
|
logger.info(f"Saved audio segment to {filename}")
|
||||||
|
|
||||||
# Transcribe the audio
|
# Transcribe the audio with German language preference
|
||||||
try:
|
try:
|
||||||
segments, info = asr_model.transcribe(
|
segments, info = asr_model.transcribe(
|
||||||
filename,
|
filename,
|
||||||
language="en",
|
language="de", # Set German as preferred language
|
||||||
beam_size=5,
|
beam_size=5,
|
||||||
temperature=0
|
temperature=0
|
||||||
)
|
)
|
||||||
|
|
||||||
# Format the transcription result
|
# Get the full transcribed text
|
||||||
result = {
|
transcribed_text = " ".join(segment.text for segment in segments)
|
||||||
"text": " ".join(segment.text for segment in segments),
|
logger.info(f"Transcribed text: {transcribed_text}")
|
||||||
"segments": [
|
|
||||||
{
|
|
||||||
"text": segment.text,
|
|
||||||
"start": segment.start,
|
|
||||||
"end": segment.end,
|
|
||||||
"confidence": segment.confidence
|
|
||||||
}
|
|
||||||
for segment in segments
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
# Save metadata and transcription
|
# Process the command
|
||||||
metadata = {
|
process_command(transcribed_text)
|
||||||
"timestamp": timestamp,
|
|
||||||
"wake_word": wake_word,
|
|
||||||
"wake_word_confidence": float(prediction[wake_word]),
|
|
||||||
"sample_rate": SAMPLE_RATE,
|
|
||||||
"channels": CHANNELS,
|
|
||||||
"duration": BUFFER_DURATION,
|
|
||||||
"transcription": result
|
|
||||||
}
|
|
||||||
|
|
||||||
with open(f"{filename}.json", 'w') as f:
|
|
||||||
json.dump(metadata, f, indent=2)
|
|
||||||
|
|
||||||
print("\nTranscription result:")
|
|
||||||
print(f"Text: {result['text']}")
|
|
||||||
print("\nSegments:")
|
|
||||||
for segment in result["segments"]:
|
|
||||||
print(f"[{segment['start']:.2f}s - {segment['end']:.2f}s] ({segment['confidence']:.2%})")
|
|
||||||
print(f'"{segment["text"]}"')
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error during transcription: {e}")
|
logger.error(f"Error during transcription or processing: {e}")
|
||||||
metadata = {
|
|
||||||
"timestamp": timestamp,
|
|
||||||
"wake_word": wake_word,
|
|
||||||
"wake_word_confidence": float(prediction[wake_word]),
|
|
||||||
"sample_rate": SAMPLE_RATE,
|
|
||||||
"channels": CHANNELS,
|
|
||||||
"duration": BUFFER_DURATION,
|
|
||||||
"error": str(e)
|
|
||||||
}
|
|
||||||
with open(f"{filename}.json", 'w') as f:
|
|
||||||
json.dump(metadata, f, indent=2)
|
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
"""Start audio processing"""
|
"""Start audio processing"""
|
||||||
try:
|
try:
|
||||||
print("Initializing wake word detection...")
|
logger.info("Starting audio processor...")
|
||||||
print(f"Loaded wake words: {', '.join(WAKE_WORDS)}")
|
|
||||||
|
|
||||||
with sd.InputStream(
|
# Log configuration
|
||||||
channels=CHANNELS,
|
logger.debug(f"Sample Rate: {SAMPLE_RATE}")
|
||||||
samplerate=SAMPLE_RATE,
|
logger.debug(f"Channels: {CHANNELS}")
|
||||||
blocksize=CHUNK_SIZE,
|
logger.debug(f"Chunk Size: {CHUNK_SIZE}")
|
||||||
callback=self.audio_callback
|
logger.debug(f"Buffer Duration: {BUFFER_DURATION}")
|
||||||
):
|
logger.debug(f"Wake Word Enabled: {WAKE_WORD_ENABLED}")
|
||||||
print("\nWake word detection started. Listening...")
|
logger.debug(f"Speech Enabled: {SPEECH_ENABLED}")
|
||||||
print("Press Ctrl+C to stop")
|
logger.debug(f"ASR Model: {os.environ.get('ASR_MODEL')}")
|
||||||
|
|
||||||
while True:
|
if WAKE_WORD_ENABLED:
|
||||||
sd.sleep(1000) # Sleep for 1 second
|
logger.info("Initializing wake word detection...")
|
||||||
|
logger.info(f"Loaded wake words: {', '.join(WAKE_WORDS)}")
|
||||||
|
else:
|
||||||
|
logger.info("Starting continuous transcription mode...")
|
||||||
|
interval = CONTINUOUS_TRANSCRIPTION_INTERVAL
|
||||||
|
logger.info(f"Will transcribe every {interval} seconds")
|
||||||
|
|
||||||
|
try:
|
||||||
|
logger.debug("Setting up audio input stream...")
|
||||||
|
with sd.InputStream(
|
||||||
|
channels=CHANNELS,
|
||||||
|
samplerate=SAMPLE_RATE,
|
||||||
|
blocksize=CHUNK_SIZE,
|
||||||
|
callback=self.audio_callback
|
||||||
|
):
|
||||||
|
logger.info("Audio input stream started successfully")
|
||||||
|
logger.info("Listening for audio input...")
|
||||||
|
logger.info("Press Ctrl+C to stop")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
sd.sleep(1000) # Sleep for 1 second
|
||||||
|
|
||||||
|
except sd.PortAudioError as e:
|
||||||
|
logger.error(f"Error setting up audio stream: {e}")
|
||||||
|
logger.error("Check if microphone is connected and accessible")
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Unexpected error in audio stream: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print("\nStopping wake word detection...")
|
logger.info("\nStopping audio processing...")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error in audio processing: {e}")
|
logger.error("Critical error in audio processing", exc_info=True)
|
||||||
|
raise
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
processor = AudioProcessor()
|
try:
|
||||||
processor.start()
|
logger.info("Initializing AudioProcessor...")
|
||||||
|
processor = AudioProcessor()
|
||||||
|
processor.start()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Failed to start AudioProcessor", exc_info=True)
|
||||||
|
raise
|
||||||
326
docs/api/core.md
Normal file
326
docs/api/core.md
Normal file
@@ -0,0 +1,326 @@
|
|||||||
|
---
|
||||||
|
layout: default
|
||||||
|
title: Core Functions
|
||||||
|
parent: API Reference
|
||||||
|
nav_order: 3
|
||||||
|
---
|
||||||
|
|
||||||
|
# Core Functions API 🔧
|
||||||
|
|
||||||
|
The Core Functions API provides the fundamental operations for interacting with Home Assistant devices and services through MCP Server.
|
||||||
|
|
||||||
|
## Device Control
|
||||||
|
|
||||||
|
### Get Device State
|
||||||
|
|
||||||
|
Retrieve the current state of devices.
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/state
|
||||||
|
GET /api/state/{entity_id}
|
||||||
|
```
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
- `entity_id` (optional): Specific device ID to query
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Get all states
|
||||||
|
curl http://localhost:3000/api/state
|
||||||
|
|
||||||
|
# Get specific device state
|
||||||
|
curl http://localhost:3000/api/state/light.living_room
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"entity_id": "light.living_room",
|
||||||
|
"state": "on",
|
||||||
|
"attributes": {
|
||||||
|
"brightness": 255,
|
||||||
|
"color_temp": 370,
|
||||||
|
"friendly_name": "Living Room Light"
|
||||||
|
},
|
||||||
|
"last_changed": "2024-01-20T15:30:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Control Device
|
||||||
|
|
||||||
|
Execute device commands.
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/device/control
|
||||||
|
```
|
||||||
|
|
||||||
|
Request body:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"entity_id": "light.living_room",
|
||||||
|
"action": "turn_on",
|
||||||
|
"parameters": {
|
||||||
|
"brightness": 200,
|
||||||
|
"color_temp": 400
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Available actions:
|
||||||
|
- `turn_on`
|
||||||
|
- `turn_off`
|
||||||
|
- `toggle`
|
||||||
|
- `set_value`
|
||||||
|
|
||||||
|
Example with curl:
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:3000/api/device/control \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
|
||||||
|
-d '{
|
||||||
|
"entity_id": "light.living_room",
|
||||||
|
"action": "turn_on",
|
||||||
|
"parameters": {
|
||||||
|
"brightness": 200
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Natural Language Commands
|
||||||
|
|
||||||
|
### Execute Command
|
||||||
|
|
||||||
|
Process natural language commands.
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/command
|
||||||
|
```
|
||||||
|
|
||||||
|
Request body:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"command": "Turn on the living room lights and set them to 50% brightness"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:3000/api/command \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
|
||||||
|
-d '{
|
||||||
|
"command": "Turn on the living room lights and set them to 50% brightness"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"actions": [
|
||||||
|
{
|
||||||
|
"entity_id": "light.living_room",
|
||||||
|
"action": "turn_on",
|
||||||
|
"parameters": {
|
||||||
|
"brightness": 127
|
||||||
|
},
|
||||||
|
"status": "completed"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"message": "Command executed successfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Scene Management
|
||||||
|
|
||||||
|
### Create Scene
|
||||||
|
|
||||||
|
Define a new scene with multiple actions.
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/scene
|
||||||
|
```
|
||||||
|
|
||||||
|
Request body:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "Movie Night",
|
||||||
|
"description": "Perfect lighting for movie watching",
|
||||||
|
"actions": [
|
||||||
|
{
|
||||||
|
"entity_id": "light.living_room",
|
||||||
|
"action": "turn_on",
|
||||||
|
"parameters": {
|
||||||
|
"brightness": 50,
|
||||||
|
"color_temp": 500
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"entity_id": "cover.living_room",
|
||||||
|
"action": "close"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Activate Scene
|
||||||
|
|
||||||
|
Trigger a predefined scene.
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/scene/{scene_name}/activate
|
||||||
|
```
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:3000/api/scene/movie_night/activate \
|
||||||
|
-H "Authorization: Bearer YOUR_JWT_TOKEN"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Groups
|
||||||
|
|
||||||
|
### Create Device Group
|
||||||
|
|
||||||
|
Create a group of devices for collective control.
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/group
|
||||||
|
```
|
||||||
|
|
||||||
|
Request body:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "Living Room",
|
||||||
|
"entities": [
|
||||||
|
"light.living_room_main",
|
||||||
|
"light.living_room_accent",
|
||||||
|
"switch.living_room_fan"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Control Group
|
||||||
|
|
||||||
|
Control multiple devices in a group.
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/group/{group_name}/control
|
||||||
|
```
|
||||||
|
|
||||||
|
Request body:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"action": "turn_off"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## System Operations
|
||||||
|
|
||||||
|
### Health Check
|
||||||
|
|
||||||
|
Check server status and connectivity.
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /health
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "healthy",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"uptime": 3600,
|
||||||
|
"homeAssistant": {
|
||||||
|
"connected": true,
|
||||||
|
"version": "2024.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
Get current server configuration.
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/config
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"server": {
|
||||||
|
"port": 3000,
|
||||||
|
"host": "0.0.0.0",
|
||||||
|
"version": "1.0.0"
|
||||||
|
},
|
||||||
|
"homeAssistant": {
|
||||||
|
"url": "http://homeassistant:8123",
|
||||||
|
"connected": true
|
||||||
|
},
|
||||||
|
"features": {
|
||||||
|
"nlp": true,
|
||||||
|
"scenes": true,
|
||||||
|
"groups": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
All endpoints follow standard HTTP status codes and return detailed error messages:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": true,
|
||||||
|
"code": "INVALID_ENTITY",
|
||||||
|
"message": "Device 'light.nonexistent' not found",
|
||||||
|
"details": {
|
||||||
|
"entity_id": "light.nonexistent",
|
||||||
|
"available_entities": [
|
||||||
|
"light.living_room",
|
||||||
|
"light.kitchen"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Common error codes:
|
||||||
|
- `INVALID_ENTITY`: Device not found
|
||||||
|
- `INVALID_ACTION`: Unsupported action
|
||||||
|
- `INVALID_PARAMETERS`: Invalid command parameters
|
||||||
|
- `AUTHENTICATION_ERROR`: Invalid or missing token
|
||||||
|
- `CONNECTION_ERROR`: Home Assistant connection issue
|
||||||
|
|
||||||
|
## TypeScript Interfaces
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface DeviceState {
|
||||||
|
entity_id: string;
|
||||||
|
state: string;
|
||||||
|
attributes: Record<string, any>;
|
||||||
|
last_changed: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeviceCommand {
|
||||||
|
entity_id: string;
|
||||||
|
action: 'turn_on' | 'turn_off' | 'toggle' | 'set_value';
|
||||||
|
parameters?: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Scene {
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
actions: DeviceCommand[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Group {
|
||||||
|
name: string;
|
||||||
|
entities: string[];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Related Resources
|
||||||
|
|
||||||
|
- [API Overview](index.md)
|
||||||
|
- [SSE API](sse.md)
|
||||||
|
- [Architecture](../architecture.md)
|
||||||
|
- [Examples](https://github.com/jango-blockchained/advanced-homeassistant-mcp/tree/main/examples)
|
||||||
234
docs/api/index.md
Normal file
234
docs/api/index.md
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
---
|
||||||
|
layout: default
|
||||||
|
title: API Overview
|
||||||
|
parent: API Reference
|
||||||
|
nav_order: 1
|
||||||
|
has_children: false
|
||||||
|
---
|
||||||
|
|
||||||
|
# API Documentation 📚
|
||||||
|
|
||||||
|
Welcome to the MCP Server API documentation. This guide covers all available endpoints, authentication methods, and integration patterns.
|
||||||
|
|
||||||
|
## API Overview
|
||||||
|
|
||||||
|
The MCP Server provides several API categories:
|
||||||
|
|
||||||
|
1. **Core API** - Basic device control and state management
|
||||||
|
2. **SSE API** - Real-time event subscriptions
|
||||||
|
3. **Scene API** - Scene management and automation
|
||||||
|
4. **Voice API** - Natural language command processing
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
All API endpoints require authentication using JWT tokens:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Include the token in your requests
|
||||||
|
curl -H "Authorization: Bearer YOUR_JWT_TOKEN" http://localhost:3000/api/state
|
||||||
|
```
|
||||||
|
|
||||||
|
To obtain a token:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:3000/auth/token \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"username": "your_username", "password": "your_password"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Core Endpoints
|
||||||
|
|
||||||
|
### Device State
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/state
|
||||||
|
```
|
||||||
|
|
||||||
|
Retrieve the current state of all devices:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://localhost:3000/api/state
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"devices": [
|
||||||
|
{
|
||||||
|
"id": "light.living_room",
|
||||||
|
"state": "on",
|
||||||
|
"attributes": {
|
||||||
|
"brightness": 255,
|
||||||
|
"color_temp": 370
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Command Execution
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/command
|
||||||
|
```
|
||||||
|
|
||||||
|
Execute a natural language command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:3000/api/command \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"command": "Turn on the kitchen lights"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"action": "turn_on",
|
||||||
|
"device": "light.kitchen",
|
||||||
|
"message": "Kitchen lights turned on"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Real-Time Events
|
||||||
|
|
||||||
|
### Event Subscription
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /subscribe_events
|
||||||
|
```
|
||||||
|
|
||||||
|
Subscribe to device state changes:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const eventSource = new EventSource('http://localhost:3000/subscribe_events?token=YOUR_TOKEN');
|
||||||
|
|
||||||
|
eventSource.onmessage = (event) => {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
console.log('State changed:', data);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Filtered Subscriptions
|
||||||
|
|
||||||
|
Subscribe to specific device types:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /subscribe_events?domain=light
|
||||||
|
GET /subscribe_events?entity_id=light.living_room
|
||||||
|
```
|
||||||
|
|
||||||
|
## Scene Management
|
||||||
|
|
||||||
|
### Create Scene
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/scene
|
||||||
|
```
|
||||||
|
|
||||||
|
Create a new scene:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:3000/api/scene \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"name": "Movie Night",
|
||||||
|
"actions": [
|
||||||
|
{"device": "light.living_room", "action": "dim", "value": 20},
|
||||||
|
{"device": "media_player.tv", "action": "on"}
|
||||||
|
]
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Activate Scene
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/scene/activate
|
||||||
|
```
|
||||||
|
|
||||||
|
Activate an existing scene:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:3000/api/scene/activate \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"name": "Movie Night"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
The API uses standard HTTP status codes:
|
||||||
|
|
||||||
|
- `200` - Success
|
||||||
|
- `400` - Bad Request
|
||||||
|
- `401` - Unauthorized
|
||||||
|
- `404` - Not Found
|
||||||
|
- `500` - Server Error
|
||||||
|
|
||||||
|
Error responses include detailed messages:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": true,
|
||||||
|
"message": "Device not found",
|
||||||
|
"code": "DEVICE_NOT_FOUND",
|
||||||
|
"details": {
|
||||||
|
"device_id": "light.nonexistent"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rate Limiting
|
||||||
|
|
||||||
|
API requests are rate-limited to prevent abuse:
|
||||||
|
|
||||||
|
```http
|
||||||
|
X-RateLimit-Limit: 100
|
||||||
|
X-RateLimit-Remaining: 99
|
||||||
|
X-RateLimit-Reset: 1640995200
|
||||||
|
```
|
||||||
|
|
||||||
|
When exceeded, returns `429 Too Many Requests`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": true,
|
||||||
|
"message": "Rate limit exceeded",
|
||||||
|
"reset": 1640995200
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## WebSocket API
|
||||||
|
|
||||||
|
For bi-directional communication:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const ws = new WebSocket('ws://localhost:3000/ws');
|
||||||
|
|
||||||
|
ws.onmessage = (event) => {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
console.log('Received:', data);
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.send(JSON.stringify({
|
||||||
|
type: 'command',
|
||||||
|
payload: {
|
||||||
|
command: 'Turn on lights'
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Versioning
|
||||||
|
|
||||||
|
The current API version is v1. Include the version in the URL:
|
||||||
|
|
||||||
|
```http
|
||||||
|
/api/v1/state
|
||||||
|
/api/v1/command
|
||||||
|
```
|
||||||
|
|
||||||
|
## Further Reading
|
||||||
|
|
||||||
|
- [SSE API Details](sse.md) - In-depth SSE documentation
|
||||||
|
- [Core Functions](core.md) - Detailed endpoint documentation
|
||||||
|
- [Architecture Overview](../architecture.md) - System design details
|
||||||
|
- [Troubleshooting](../troubleshooting.md) - Common issues and solutions
|
||||||
266
docs/api/sse.md
Normal file
266
docs/api/sse.md
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
---
|
||||||
|
layout: default
|
||||||
|
title: SSE API
|
||||||
|
parent: API Reference
|
||||||
|
nav_order: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
# Server-Sent Events (SSE) API 📡
|
||||||
|
|
||||||
|
The SSE API provides real-time updates about device states and events from your Home Assistant setup. This guide covers how to use and implement SSE connections in your applications.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Server-Sent Events (SSE) is a standard that enables servers to push real-time updates to clients over HTTP connections. MCP Server uses SSE to provide:
|
||||||
|
|
||||||
|
- Real-time device state updates
|
||||||
|
- Event notifications
|
||||||
|
- System status changes
|
||||||
|
- Command execution results
|
||||||
|
|
||||||
|
## Basic Usage
|
||||||
|
|
||||||
|
### Establishing a Connection
|
||||||
|
|
||||||
|
Create an EventSource connection to receive updates:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const eventSource = new EventSource('http://localhost:3000/subscribe_events?token=YOUR_JWT_TOKEN');
|
||||||
|
|
||||||
|
eventSource.onmessage = (event) => {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
console.log('Received update:', data);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Connection States
|
||||||
|
|
||||||
|
Handle different connection states:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
eventSource.onopen = () => {
|
||||||
|
console.log('Connection established');
|
||||||
|
};
|
||||||
|
|
||||||
|
eventSource.onerror = (error) => {
|
||||||
|
console.error('Connection error:', error);
|
||||||
|
// Implement reconnection logic if needed
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Event Types
|
||||||
|
|
||||||
|
### Device State Events
|
||||||
|
|
||||||
|
Subscribe to all device state changes:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const stateEvents = new EventSource('http://localhost:3000/subscribe_events?type=state');
|
||||||
|
|
||||||
|
stateEvents.onmessage = (event) => {
|
||||||
|
const state = JSON.parse(event.data);
|
||||||
|
console.log('Device state changed:', state);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Example state event:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "state_changed",
|
||||||
|
"entity_id": "light.living_room",
|
||||||
|
"state": "on",
|
||||||
|
"attributes": {
|
||||||
|
"brightness": 255,
|
||||||
|
"color_temp": 370
|
||||||
|
},
|
||||||
|
"timestamp": "2024-01-20T15:30:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Filtered Subscriptions
|
||||||
|
|
||||||
|
#### By Domain
|
||||||
|
Subscribe to specific device types:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Subscribe to only light events
|
||||||
|
const lightEvents = new EventSource('http://localhost:3000/subscribe_events?domain=light');
|
||||||
|
|
||||||
|
// Subscribe to multiple domains
|
||||||
|
const multiEvents = new EventSource('http://localhost:3000/subscribe_events?domain=light,switch,sensor');
|
||||||
|
```
|
||||||
|
|
||||||
|
#### By Entity ID
|
||||||
|
Subscribe to specific devices:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Single entity
|
||||||
|
const livingRoomLight = new EventSource(
|
||||||
|
'http://localhost:3000/subscribe_events?entity_id=light.living_room'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Multiple entities
|
||||||
|
const kitchenDevices = new EventSource(
|
||||||
|
'http://localhost:3000/subscribe_events?entity_id=light.kitchen,switch.coffee_maker'
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Advanced Usage
|
||||||
|
|
||||||
|
### Connection Management
|
||||||
|
|
||||||
|
Implement robust connection handling:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
class SSEManager {
|
||||||
|
constructor(url, options = {}) {
|
||||||
|
this.url = url;
|
||||||
|
this.options = {
|
||||||
|
maxRetries: 3,
|
||||||
|
retryDelay: 1000,
|
||||||
|
...options
|
||||||
|
};
|
||||||
|
this.retryCount = 0;
|
||||||
|
this.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
this.eventSource = new EventSource(this.url);
|
||||||
|
|
||||||
|
this.eventSource.onopen = () => {
|
||||||
|
this.retryCount = 0;
|
||||||
|
console.log('Connected to SSE stream');
|
||||||
|
};
|
||||||
|
|
||||||
|
this.eventSource.onerror = (error) => {
|
||||||
|
this.handleError(error);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.eventSource.onmessage = (event) => {
|
||||||
|
this.handleMessage(event);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
handleError(error) {
|
||||||
|
console.error('SSE Error:', error);
|
||||||
|
this.eventSource.close();
|
||||||
|
|
||||||
|
if (this.retryCount < this.options.maxRetries) {
|
||||||
|
this.retryCount++;
|
||||||
|
setTimeout(() => {
|
||||||
|
console.log(`Retrying connection (${this.retryCount}/${this.options.maxRetries})`);
|
||||||
|
this.connect();
|
||||||
|
}, this.options.retryDelay * this.retryCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleMessage(event) {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
// Handle the event data
|
||||||
|
console.log('Received:', data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error parsing SSE data:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect() {
|
||||||
|
if (this.eventSource) {
|
||||||
|
this.eventSource.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
const sseManager = new SSEManager('http://localhost:3000/subscribe_events?token=YOUR_TOKEN');
|
||||||
|
```
|
||||||
|
|
||||||
|
### Event Filtering
|
||||||
|
|
||||||
|
Filter events on the client side:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
class EventFilter {
|
||||||
|
constructor(conditions) {
|
||||||
|
this.conditions = conditions;
|
||||||
|
}
|
||||||
|
|
||||||
|
matches(event) {
|
||||||
|
return Object.entries(this.conditions).every(([key, value]) => {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value.includes(event[key]);
|
||||||
|
}
|
||||||
|
return event[key] === value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
const filter = new EventFilter({
|
||||||
|
domain: ['light', 'switch'],
|
||||||
|
state: 'on'
|
||||||
|
});
|
||||||
|
|
||||||
|
eventSource.onmessage = (event) => {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
if (filter.matches(data)) {
|
||||||
|
console.log('Matched event:', data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Authentication**
|
||||||
|
- Always include authentication tokens
|
||||||
|
- Implement token refresh mechanisms
|
||||||
|
- Handle authentication errors gracefully
|
||||||
|
|
||||||
|
2. **Error Handling**
|
||||||
|
- Implement progressive retry logic
|
||||||
|
- Log connection issues
|
||||||
|
- Notify users of connection status
|
||||||
|
|
||||||
|
3. **Resource Management**
|
||||||
|
- Close EventSource connections when not needed
|
||||||
|
- Limit the number of concurrent connections
|
||||||
|
- Use filtered subscriptions when possible
|
||||||
|
|
||||||
|
4. **Performance**
|
||||||
|
- Process events efficiently
|
||||||
|
- Batch UI updates
|
||||||
|
- Consider debouncing frequent updates
|
||||||
|
|
||||||
|
## Common Issues
|
||||||
|
|
||||||
|
### Connection Drops
|
||||||
|
If the connection drops, the EventSource will automatically attempt to reconnect. You can customize this behavior:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
eventSource.addEventListener('error', (error) => {
|
||||||
|
if (eventSource.readyState === EventSource.CLOSED) {
|
||||||
|
// Connection closed, implement custom retry logic
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Memory Leaks
|
||||||
|
Always clean up EventSource connections:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// In a React component
|
||||||
|
useEffect(() => {
|
||||||
|
const eventSource = new EventSource('http://localhost:3000/subscribe_events');
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
eventSource.close(); // Cleanup on unmount
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Related Resources
|
||||||
|
|
||||||
|
- [API Overview](index.md)
|
||||||
|
- [Core Functions](core.md)
|
||||||
|
- [WebSocket API](index.md#websocket-api)
|
||||||
|
- [Troubleshooting](../troubleshooting.md)
|
||||||
@@ -1,68 +1,283 @@
|
|||||||
# Architecture Documentation for MCP Server
|
---
|
||||||
|
layout: default
|
||||||
|
title: Architecture
|
||||||
|
nav_order: 4
|
||||||
|
---
|
||||||
|
|
||||||
## Overview
|
# Architecture Overview 🏗️
|
||||||
|
|
||||||
The MCP Server is designed as a high-performance, secure, and scalable bridge between Home Assistant and Language Learning Models (LLMs). This document outlines the architectural design principles, core components, and deployment strategies that power the MCP Server.
|
This document describes the architecture of the MCP Server, explaining how different components work together to provide a bridge between Home Assistant and Language Learning Models.
|
||||||
|
|
||||||
## Key Architectural Components
|
## System Architecture
|
||||||
|
|
||||||
### High-Performance Runtime with Bun
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
subgraph "Client Layer"
|
||||||
|
WC[Web Clients]
|
||||||
|
MC[Mobile Clients]
|
||||||
|
VC[Voice Assistants]
|
||||||
|
end
|
||||||
|
|
||||||
- **Fast Startup & Efficiency:** Powered by Bun, the MCP Server benefits from rapid startup times, efficient memory utilization, and native TypeScript support.
|
subgraph "MCP Server"
|
||||||
- **Optimized Build Process:** Bun's build tools allow for quick iteration and deployment, ensuring minimal downtime and swift performance enhancement.
|
API[API Gateway]
|
||||||
|
NLP[NLP Engine]
|
||||||
|
SSE[SSE Manager]
|
||||||
|
WS[WebSocket Server]
|
||||||
|
CM[Command Manager]
|
||||||
|
SC[Scene Controller]
|
||||||
|
Cache[Redis Cache]
|
||||||
|
end
|
||||||
|
|
||||||
### Real-time Communication using Server-Sent Events (SSE)
|
subgraph "Home Assistant"
|
||||||
|
HA[Home Assistant Core]
|
||||||
|
Dev[Devices & Services]
|
||||||
|
end
|
||||||
|
|
||||||
- **Continuous Updates:** The server leverages SSE to deliver real-time notifications and updates, ensuring that any changes in Home Assistant are immediately communicated to connected clients.
|
subgraph "AI Layer"
|
||||||
- **Scalable Connection Handling:** SSE provides an event-driven model that efficiently manages multiple simultaneous client connections.
|
LLM[Language Models]
|
||||||
|
IC[Intent Classifier]
|
||||||
|
NER[Named Entity Recognition]
|
||||||
|
end
|
||||||
|
|
||||||
### Modular & Extensible Design
|
WC --> |HTTP/WS| API
|
||||||
|
MC --> |HTTP/WS| API
|
||||||
|
VC --> |HTTP| API
|
||||||
|
|
||||||
- **Plugin Architecture:** Designed with modularity in mind, the MCP Server supports plugins, add-ons, and custom automation scripts, enabling seamless feature expansion without disrupting core functionality.
|
API --> |Events| SSE
|
||||||
- **Separation of Concerns:** Different components, such as device management, automation control, and system monitoring, are clearly separated, allowing independent development, testing, and scaling.
|
API --> |Real-time| WS
|
||||||
|
API --> |Process| NLP
|
||||||
|
|
||||||
### Secure API Integration
|
NLP --> |Query| LLM
|
||||||
|
NLP --> |Extract| IC
|
||||||
|
NLP --> |Identify| NER
|
||||||
|
|
||||||
- **Token-Based Authentication:** Robust token-based authentication mechanisms restrict access to authorized users and systems.
|
CM --> |Execute| HA
|
||||||
- **Rate Limiting & Error Handling:** Integrated rate limiting combined with comprehensive error handling ensures system stability and prevents misuse.
|
HA --> |Control| Dev
|
||||||
- **Best Practices:** All API endpoints follow industry-standard security guidelines to protect data and maintain system integrity.
|
|
||||||
|
|
||||||
### Deployment & Scalability
|
SSE --> |State Updates| WC
|
||||||
|
SSE --> |State Updates| MC
|
||||||
|
WS --> |Bi-directional| WC
|
||||||
|
|
||||||
- **Containerized Deployment with Docker:** The use of Docker Compose enables straightforward deployment, management, and scaling of the server and its dependencies.
|
Cache --> |Fast Access| API
|
||||||
- **Flexible Environment Configuration:** Environment variables and configuration files (.env) facilitate smooth transitions between development, testing, and production setups.
|
HA --> |Events| Cache
|
||||||
|
```
|
||||||
|
|
||||||
## Future Enhancements
|
## Component Details
|
||||||
|
|
||||||
- **Advanced Automation Logic:** Integration of more complex automation rules and conditional decision-making capabilities.
|
### 1. Client Layer
|
||||||
- **Enhanced Security Measures:** Additional layers of security, such as multi-factor authentication and improved encryption techniques, are on the roadmap.
|
|
||||||
- **Improved Monitoring & Analytics:** Future updates will introduce advanced performance metrics and real-time analytics to monitor system health and user interactions.
|
|
||||||
|
|
||||||
## Conclusion
|
The client layer consists of various interfaces that interact with the MCP Server:
|
||||||
|
|
||||||
The architecture of the MCP Server prioritizes performance, scalability, and security. By leveraging Bun's high-performance runtime, employing real-time communication through SSE, and maintaining a modular, secure design, the MCP Server provides a robust platform for integrating Home Assistant with modern LLM functionalities.
|
- **Web Clients**: Browser-based dashboards and control panels
|
||||||
|
- **Mobile Clients**: Native mobile applications
|
||||||
|
- **Voice Assistants**: Voice-enabled devices and interfaces
|
||||||
|
|
||||||
*This document is a living document and will be updated as the system evolves.*
|
### 2. MCP Server Core
|
||||||
|
|
||||||
## Key Components
|
#### API Gateway
|
||||||
|
- Handles all incoming HTTP requests
|
||||||
|
- Manages authentication and rate limiting
|
||||||
|
- Routes requests to appropriate handlers
|
||||||
|
|
||||||
- **API Module:** Handles RESTful endpoints, authentication, and error management.
|
```typescript
|
||||||
- **SSE Module:** Provides real-time updates through Server-Sent Events.
|
interface APIGateway {
|
||||||
- **Tools Module:** Offers various utilities for device control, automation, and data processing.
|
authenticate(): Promise<boolean>;
|
||||||
- **Security Module:** Implements token-based authentication and secure communications.
|
rateLimit(): Promise<boolean>;
|
||||||
- **Integration Module:** Bridges data between Home Assistant and external systems.
|
route(request: Request): Promise<Response>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### NLP Engine
|
||||||
|
- Processes natural language commands
|
||||||
|
- Integrates with Language Models
|
||||||
|
- Extracts intents and entities
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface NLPEngine {
|
||||||
|
processCommand(text: string): Promise<CommandIntent>;
|
||||||
|
extractEntities(text: string): Promise<Entity[]>;
|
||||||
|
validateIntent(intent: CommandIntent): boolean;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Event Management
|
||||||
|
- **SSE Manager**: Handles Server-Sent Events
|
||||||
|
- **WebSocket Server**: Manages bi-directional communication
|
||||||
|
- **Command Manager**: Processes and executes commands
|
||||||
|
|
||||||
|
### 3. Home Assistant Integration
|
||||||
|
|
||||||
|
The server maintains a robust connection to Home Assistant through:
|
||||||
|
|
||||||
|
- REST API calls
|
||||||
|
- WebSocket connections
|
||||||
|
- Event subscriptions
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface HomeAssistantClient {
|
||||||
|
connect(): Promise<void>;
|
||||||
|
getState(entityId: string): Promise<EntityState>;
|
||||||
|
executeCommand(command: Command): Promise<CommandResult>;
|
||||||
|
subscribeToEvents(callback: EventCallback): Subscription;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. AI Layer
|
||||||
|
|
||||||
|
#### Language Model Integration
|
||||||
|
- Processes natural language input
|
||||||
|
- Understands context and user intent
|
||||||
|
- Generates appropriate responses
|
||||||
|
|
||||||
|
#### Intent Classification
|
||||||
|
- Identifies command types
|
||||||
|
- Extracts parameters
|
||||||
|
- Validates requests
|
||||||
|
|
||||||
## Data Flow
|
## Data Flow
|
||||||
|
|
||||||
1. Requests enter via the API endpoints.
|
### 1. Command Processing
|
||||||
2. Security middleware validates and processes requests.
|
|
||||||
3. Core modules process data and execute the necessary business logic.
|
|
||||||
4. Real-time notifications are managed by the SSE module.
|
|
||||||
|
|
||||||
## Future Enhancements
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant Client
|
||||||
|
participant API
|
||||||
|
participant NLP
|
||||||
|
participant LLM
|
||||||
|
participant HA
|
||||||
|
|
||||||
- Expand modularity with potential microservices.
|
Client->>API: Send command
|
||||||
- Enhance security with multi-factor authentication.
|
API->>NLP: Process text
|
||||||
- Improve scalability through distributed architectures.
|
NLP->>LLM: Get intent
|
||||||
|
LLM-->>NLP: Return structured intent
|
||||||
|
NLP->>HA: Execute command
|
||||||
|
HA-->>API: Return result
|
||||||
|
API-->>Client: Send response
|
||||||
|
```
|
||||||
|
|
||||||
*Further diagrams and detailed breakdowns will be added in future updates.*
|
### 2. Real-time Updates
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant HA
|
||||||
|
participant Cache
|
||||||
|
participant SSE
|
||||||
|
participant Client
|
||||||
|
|
||||||
|
HA->>Cache: State change
|
||||||
|
Cache->>SSE: Notify change
|
||||||
|
SSE->>Client: Send update
|
||||||
|
Note over Client: Update UI
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. [SSE API](api/sse.md)
|
||||||
|
- Event Subscriptions
|
||||||
|
- Real-time Updates
|
||||||
|
- Connection Management
|
||||||
|
|
||||||
|
## Security Architecture
|
||||||
|
|
||||||
|
### Authentication Flow
|
||||||
|
|
||||||
|
1. **JWT-based Authentication**
|
||||||
|
```typescript
|
||||||
|
interface AuthToken {
|
||||||
|
token: string;
|
||||||
|
expires: number;
|
||||||
|
scope: string[];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Rate Limiting**
|
||||||
|
```typescript
|
||||||
|
interface RateLimit {
|
||||||
|
window: number;
|
||||||
|
max: number;
|
||||||
|
current: number;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Security Measures
|
||||||
|
|
||||||
|
- TLS encryption for all communications
|
||||||
|
- Input sanitization
|
||||||
|
- Request validation
|
||||||
|
- Token-based authentication
|
||||||
|
- Rate limiting
|
||||||
|
- IP filtering
|
||||||
|
|
||||||
|
## Performance Optimizations
|
||||||
|
|
||||||
|
### Caching Strategy
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
Request --> Cache{Cache?}
|
||||||
|
Cache -->|Hit| Response
|
||||||
|
Cache -->|Miss| HA[Home Assistant]
|
||||||
|
HA --> Cache
|
||||||
|
Cache --> Response
|
||||||
|
```
|
||||||
|
|
||||||
|
### Connection Management
|
||||||
|
|
||||||
|
- Connection pooling
|
||||||
|
- Automatic reconnection
|
||||||
|
- Load balancing
|
||||||
|
- Request queuing
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
The system is highly configurable through environment variables and configuration files:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
server:
|
||||||
|
port: 3000
|
||||||
|
host: '0.0.0.0'
|
||||||
|
|
||||||
|
homeAssistant:
|
||||||
|
url: 'http://homeassistant:8123'
|
||||||
|
token: 'YOUR_TOKEN'
|
||||||
|
|
||||||
|
security:
|
||||||
|
jwtSecret: 'your-secret'
|
||||||
|
rateLimit: 100
|
||||||
|
|
||||||
|
ai:
|
||||||
|
model: 'gpt-4'
|
||||||
|
temperature: 0.7
|
||||||
|
|
||||||
|
cache:
|
||||||
|
ttl: 300
|
||||||
|
maxSize: '100mb'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deployment Architecture
|
||||||
|
|
||||||
|
### Docker Deployment
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
subgraph "Docker Compose"
|
||||||
|
MCP[MCP Server]
|
||||||
|
Redis[Redis Cache]
|
||||||
|
HA[Home Assistant]
|
||||||
|
end
|
||||||
|
|
||||||
|
MCP --> Redis
|
||||||
|
MCP --> HA
|
||||||
|
```
|
||||||
|
|
||||||
|
### Scaling Considerations
|
||||||
|
|
||||||
|
- Horizontal scaling capabilities
|
||||||
|
- Load balancing support
|
||||||
|
- Redis cluster support
|
||||||
|
- Multiple HA instance support
|
||||||
|
|
||||||
|
## Further Reading
|
||||||
|
|
||||||
|
- [API Documentation](api/index.md)
|
||||||
|
- [Installation Guide](getting-started/installation.md)
|
||||||
|
- [Contributing Guidelines](contributing.md)
|
||||||
|
- [Troubleshooting](troubleshooting.md)
|
||||||
28
docs/assets/stylesheets/extra.css
Normal file
28
docs/assets/stylesheets/extra.css
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
:root {
|
||||||
|
--md-primary-fg-color: #1a73e8;
|
||||||
|
--md-primary-fg-color--light: #5195ee;
|
||||||
|
--md-primary-fg-color--dark: #0d47a1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-header {
|
||||||
|
box-shadow: 0 0 0.2rem rgba(0,0,0,.1), 0 0.2rem 0.4rem rgba(0,0,0,.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-main__inner {
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-typeset h1 {
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--md-primary-fg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-typeset .admonition {
|
||||||
|
font-size: .8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
background-color: rgba(175,184,193,0.2);
|
||||||
|
padding: .2em .4em;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
16
docs/claude_desktop_config.json
Normal file
16
docs/claude_desktop_config.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"homeassistant-mcp": {
|
||||||
|
"command": "bun",
|
||||||
|
"args": [
|
||||||
|
"run",
|
||||||
|
"start",
|
||||||
|
"--port",
|
||||||
|
"8080"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"NODE_ENV": "production"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
docs/cline_config.json
Normal file
18
docs/cline_config.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"homeassistant-mcp": {
|
||||||
|
"command": "bun",
|
||||||
|
"args": [
|
||||||
|
"run",
|
||||||
|
"start",
|
||||||
|
"--enable-cline",
|
||||||
|
"--config",
|
||||||
|
"${configDir}/.env"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"NODE_ENV": "production",
|
||||||
|
"CLINE_MODE": "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,36 +1,254 @@
|
|||||||
# Contributing to Home Assistant MCP
|
---
|
||||||
|
layout: default
|
||||||
|
title: Contributing
|
||||||
|
nav_order: 5
|
||||||
|
---
|
||||||
|
|
||||||
We welcome community contributions to improve the MCP Server. Please review the following guidelines before contributing.
|
# Contributing Guide 🤝
|
||||||
|
|
||||||
## How to Contribute
|
Thank you for your interest in contributing to the MCP Server project! This guide will help you get started with contributing to the project.
|
||||||
|
|
||||||
1. **Fork the Repository:** Create your personal fork on GitHub.
|
## Getting Started
|
||||||
2. **Create a Feature Branch:** Use a clear name (e.g., `feature/your-feature` or `bugfix/short-description`).
|
|
||||||
3. **Make Changes:** Develop your feature or fix bugs while following our coding standards.
|
|
||||||
4. **Write Tests:** Include tests for new features or bug fixes.
|
|
||||||
5. **Submit a Pull Request:** Once your changes are complete, submit a PR for review.
|
|
||||||
6. **Address Feedback:** Revise your PR based on maintainers' suggestions.
|
|
||||||
|
|
||||||
## Code Style Guidelines
|
### Prerequisites
|
||||||
|
|
||||||
- Follow the project's established coding style.
|
Before you begin, ensure you have:
|
||||||
- Use Bun tooling for linting and formatting:
|
|
||||||
- `bun run lint`
|
- [Bun](https://bun.sh) >= 1.0.26
|
||||||
- `bun run format`
|
- [Node.js](https://nodejs.org) >= 18
|
||||||
|
- [Docker](https://www.docker.com) (optional, for containerized development)
|
||||||
|
- A running Home Assistant instance for testing
|
||||||
|
|
||||||
|
### Development Setup
|
||||||
|
|
||||||
|
1. Fork and clone the repository:
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/YOUR_USERNAME/advanced-homeassistant-mcp.git
|
||||||
|
cd advanced-homeassistant-mcp
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Install dependencies:
|
||||||
|
```bash
|
||||||
|
bun install
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Set up your development environment:
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
# Edit .env with your Home Assistant details
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Start the development server:
|
||||||
|
```bash
|
||||||
|
bun run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development Workflow
|
||||||
|
|
||||||
|
### Branch Naming Convention
|
||||||
|
|
||||||
|
- `feature/` - New features
|
||||||
|
- `fix/` - Bug fixes
|
||||||
|
- `docs/` - Documentation updates
|
||||||
|
- `refactor/` - Code refactoring
|
||||||
|
- `test/` - Test improvements
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```bash
|
||||||
|
git checkout -b feature/voice-commands
|
||||||
|
```
|
||||||
|
|
||||||
|
### Commit Messages
|
||||||
|
|
||||||
|
We follow the [Conventional Commits](https://www.conventionalcommits.org/) specification:
|
||||||
|
|
||||||
|
```
|
||||||
|
type(scope): description
|
||||||
|
|
||||||
|
[optional body]
|
||||||
|
|
||||||
|
[optional footer]
|
||||||
|
```
|
||||||
|
|
||||||
|
Types:
|
||||||
|
- `feat:` - New features
|
||||||
|
- `fix:` - Bug fixes
|
||||||
|
- `docs:` - Documentation changes
|
||||||
|
- `style:` - Code style changes (formatting, etc.)
|
||||||
|
- `refactor:` - Code refactoring
|
||||||
|
- `test:` - Test updates
|
||||||
|
- `chore:` - Maintenance tasks
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
```bash
|
||||||
|
feat(api): add voice command endpoint
|
||||||
|
fix(sse): resolve connection timeout issue
|
||||||
|
docs(readme): update installation instructions
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
Run tests before submitting your changes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run all tests
|
||||||
|
bun test
|
||||||
|
|
||||||
|
# Run specific test file
|
||||||
|
bun test test/api/command.test.ts
|
||||||
|
|
||||||
|
# Run tests with coverage
|
||||||
|
bun test --coverage
|
||||||
|
```
|
||||||
|
|
||||||
|
### Code Style
|
||||||
|
|
||||||
|
We use ESLint and Prettier for code formatting:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check code style
|
||||||
|
bun run lint
|
||||||
|
|
||||||
|
# Fix code style issues
|
||||||
|
bun run lint:fix
|
||||||
|
```
|
||||||
|
|
||||||
|
## Pull Request Process
|
||||||
|
|
||||||
|
1. **Update Documentation**
|
||||||
|
- Add/update relevant documentation
|
||||||
|
- Include inline code comments where necessary
|
||||||
|
- Update API documentation if endpoints change
|
||||||
|
|
||||||
|
2. **Write Tests**
|
||||||
|
- Add tests for new features
|
||||||
|
- Update existing tests if needed
|
||||||
|
- Ensure all tests pass
|
||||||
|
|
||||||
|
3. **Create Pull Request**
|
||||||
|
- Fill out the PR template
|
||||||
|
- Link related issues
|
||||||
|
- Provide clear description of changes
|
||||||
|
|
||||||
|
4. **Code Review**
|
||||||
|
- Address review comments
|
||||||
|
- Keep discussions focused
|
||||||
|
- Be patient and respectful
|
||||||
|
|
||||||
|
### PR Template
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## Description
|
||||||
|
Brief description of the changes
|
||||||
|
|
||||||
|
## Type of Change
|
||||||
|
- [ ] Bug fix
|
||||||
|
- [ ] New feature
|
||||||
|
- [ ] Breaking change
|
||||||
|
- [ ] Documentation update
|
||||||
|
|
||||||
|
## How Has This Been Tested?
|
||||||
|
Describe your test process
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
- [ ] Tests added/updated
|
||||||
|
- [ ] Documentation updated
|
||||||
|
- [ ] Code follows style guidelines
|
||||||
|
- [ ] All tests passing
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development Guidelines
|
||||||
|
|
||||||
|
### Code Organization
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
├── api/ # API endpoints
|
||||||
|
├── core/ # Core functionality
|
||||||
|
├── models/ # Data models
|
||||||
|
├── services/ # Business logic
|
||||||
|
├── utils/ # Utility functions
|
||||||
|
└── types/ # TypeScript types
|
||||||
|
```
|
||||||
|
|
||||||
|
### Best Practices
|
||||||
|
|
||||||
|
1. **Type Safety**
|
||||||
|
```typescript
|
||||||
|
// Use explicit types
|
||||||
|
interface CommandRequest {
|
||||||
|
command: string;
|
||||||
|
parameters?: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function processCommand(request: CommandRequest): Promise<CommandResponse> {
|
||||||
|
// Implementation
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Error Handling**
|
||||||
|
```typescript
|
||||||
|
try {
|
||||||
|
await processCommand(request);
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof ValidationError) {
|
||||||
|
// Handle validation errors
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Async/Await**
|
||||||
|
```typescript
|
||||||
|
// Prefer async/await over promises
|
||||||
|
async function handleRequest() {
|
||||||
|
const result = await processData();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
- Update documentation alongside your code changes.
|
### API Documentation
|
||||||
- Ensure tests pass and coverage remains high.
|
|
||||||
|
|
||||||
## Reporting Issues
|
Update API documentation when adding/modifying endpoints:
|
||||||
|
|
||||||
- Use the GitHub Issues page to report bugs, request new features, or ask questions.
|
```typescript
|
||||||
- Provide clear descriptions, replication steps, and any error logs.
|
/**
|
||||||
|
* Process a voice command
|
||||||
|
* @param command - The voice command to process
|
||||||
|
* @returns Promise<CommandResult>
|
||||||
|
* @throws {ValidationError} If command is invalid
|
||||||
|
*/
|
||||||
|
async function processVoiceCommand(command: string): Promise<CommandResult> {
|
||||||
|
// Implementation
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Community
|
### README Updates
|
||||||
|
|
||||||
- Join our real-time discussions on our chat platforms (Discord, Slack, etc.).
|
Keep the README up to date with:
|
||||||
- Engage with other contributors to exchange ideas and solutions.
|
- New features
|
||||||
|
- Changed requirements
|
||||||
|
- Updated examples
|
||||||
|
- Modified configuration
|
||||||
|
|
||||||
Thank you for helping improve the Home Assistant MCP project!
|
## Getting Help
|
||||||
|
|
||||||
|
- Check [Discussions](https://github.com/jango-blockchained/advanced-homeassistant-mcp/discussions)
|
||||||
|
- Review existing [Issues](https://github.com/jango-blockchained/advanced-homeassistant-mcp/issues)
|
||||||
|
|
||||||
|
## Community Guidelines
|
||||||
|
|
||||||
|
We expect all contributors to:
|
||||||
|
|
||||||
|
- Be respectful and inclusive
|
||||||
|
- Focus on constructive feedback
|
||||||
|
- Help maintain a positive environment
|
||||||
|
- Follow our code style guidelines
|
||||||
|
- Write clear documentation
|
||||||
|
- Test their code thoroughly
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
By contributing, you agree that your contributions will be licensed under the MIT License.
|
||||||
310
docs/development/best-practices.md
Normal file
310
docs/development/best-practices.md
Normal file
@@ -0,0 +1,310 @@
|
|||||||
|
# Development Best Practices
|
||||||
|
|
||||||
|
This guide outlines the best practices for developing tools and features for the Home Assistant MCP.
|
||||||
|
|
||||||
|
## Code Style
|
||||||
|
|
||||||
|
### TypeScript
|
||||||
|
|
||||||
|
1. Use TypeScript for all new code
|
||||||
|
2. Enable strict mode
|
||||||
|
3. Use explicit types
|
||||||
|
4. Avoid `any` type
|
||||||
|
5. Use interfaces over types
|
||||||
|
6. Document with JSDoc comments
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* Represents a device in the system.
|
||||||
|
* @interface
|
||||||
|
*/
|
||||||
|
interface Device {
|
||||||
|
/** Unique device identifier */
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
/** Human-readable device name */
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
/** Device state */
|
||||||
|
state: DeviceState;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Naming Conventions
|
||||||
|
|
||||||
|
1. Use PascalCase for:
|
||||||
|
- Classes
|
||||||
|
- Interfaces
|
||||||
|
- Types
|
||||||
|
- Enums
|
||||||
|
|
||||||
|
2. Use camelCase for:
|
||||||
|
- Variables
|
||||||
|
- Functions
|
||||||
|
- Methods
|
||||||
|
- Properties
|
||||||
|
|
||||||
|
3. Use UPPER_SNAKE_CASE for:
|
||||||
|
- Constants
|
||||||
|
- Enum values
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
class DeviceManager {
|
||||||
|
private readonly DEFAULT_TIMEOUT = 5000;
|
||||||
|
|
||||||
|
async getDeviceState(deviceId: string): Promise<DeviceState> {
|
||||||
|
// Implementation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### SOLID Principles
|
||||||
|
|
||||||
|
1. Single Responsibility
|
||||||
|
- Each class/module has one job
|
||||||
|
- Split complex functionality
|
||||||
|
|
||||||
|
2. Open/Closed
|
||||||
|
- Open for extension
|
||||||
|
- Closed for modification
|
||||||
|
|
||||||
|
3. Liskov Substitution
|
||||||
|
- Subtypes must be substitutable
|
||||||
|
- Use interfaces properly
|
||||||
|
|
||||||
|
4. Interface Segregation
|
||||||
|
- Keep interfaces focused
|
||||||
|
- Split large interfaces
|
||||||
|
|
||||||
|
5. Dependency Inversion
|
||||||
|
- Depend on abstractions
|
||||||
|
- Use dependency injection
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Bad
|
||||||
|
class DeviceManager {
|
||||||
|
async getState() { /* ... */ }
|
||||||
|
async setState() { /* ... */ }
|
||||||
|
async sendNotification() { /* ... */ } // Wrong responsibility
|
||||||
|
}
|
||||||
|
|
||||||
|
// Good
|
||||||
|
class DeviceManager {
|
||||||
|
constructor(
|
||||||
|
private notifier: NotificationService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async getState() { /* ... */ }
|
||||||
|
async setState() { /* ... */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
class NotificationService {
|
||||||
|
async send() { /* ... */ }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
### Best Practices
|
||||||
|
|
||||||
|
1. Use custom error classes
|
||||||
|
2. Include error codes
|
||||||
|
3. Provide meaningful messages
|
||||||
|
4. Include error context
|
||||||
|
5. Handle async errors
|
||||||
|
6. Log appropriately
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
class DeviceError extends Error {
|
||||||
|
constructor(
|
||||||
|
message: string,
|
||||||
|
public code: string,
|
||||||
|
public context: Record<string, any>
|
||||||
|
) {
|
||||||
|
super(message);
|
||||||
|
this.name = 'DeviceError';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await device.connect();
|
||||||
|
} catch (error) {
|
||||||
|
throw new DeviceError(
|
||||||
|
'Failed to connect to device',
|
||||||
|
'DEVICE_CONNECTION_ERROR',
|
||||||
|
{ deviceId: device.id, attempt: 1 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
### Guidelines
|
||||||
|
|
||||||
|
1. Write unit tests first
|
||||||
|
2. Use meaningful descriptions
|
||||||
|
3. Test edge cases
|
||||||
|
4. Mock external dependencies
|
||||||
|
5. Keep tests focused
|
||||||
|
6. Use test fixtures
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
describe('DeviceManager', () => {
|
||||||
|
let manager: DeviceManager;
|
||||||
|
let mockDevice: jest.Mocked<Device>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mockDevice = {
|
||||||
|
id: 'test_device',
|
||||||
|
getState: jest.fn()
|
||||||
|
};
|
||||||
|
manager = new DeviceManager(mockDevice);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get device state', async () => {
|
||||||
|
mockDevice.getState.mockResolvedValue('on');
|
||||||
|
const state = await manager.getDeviceState();
|
||||||
|
expect(state).toBe('on');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
### Optimization
|
||||||
|
|
||||||
|
1. Use caching
|
||||||
|
2. Implement pagination
|
||||||
|
3. Optimize database queries
|
||||||
|
4. Use connection pooling
|
||||||
|
5. Implement rate limiting
|
||||||
|
6. Batch operations
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
class DeviceCache {
|
||||||
|
private cache = new Map<string, CacheEntry>();
|
||||||
|
private readonly TTL = 60000; // 1 minute
|
||||||
|
|
||||||
|
async getDevice(id: string): Promise<Device> {
|
||||||
|
const cached = this.cache.get(id);
|
||||||
|
if (cached && Date.now() - cached.timestamp < this.TTL) {
|
||||||
|
return cached.device;
|
||||||
|
}
|
||||||
|
|
||||||
|
const device = await this.fetchDevice(id);
|
||||||
|
this.cache.set(id, {
|
||||||
|
device,
|
||||||
|
timestamp: Date.now()
|
||||||
|
});
|
||||||
|
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
### Guidelines
|
||||||
|
|
||||||
|
1. Validate all input
|
||||||
|
2. Use parameterized queries
|
||||||
|
3. Implement rate limiting
|
||||||
|
4. Use proper authentication
|
||||||
|
5. Follow OWASP guidelines
|
||||||
|
6. Sanitize output
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
class InputValidator {
|
||||||
|
static validateDeviceId(id: string): boolean {
|
||||||
|
return /^[a-zA-Z0-9_-]{1,64}$/.test(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static sanitizeOutput(data: any): any {
|
||||||
|
// Implement output sanitization
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
### Standards
|
||||||
|
|
||||||
|
1. Use JSDoc comments
|
||||||
|
2. Document interfaces
|
||||||
|
3. Include examples
|
||||||
|
4. Document errors
|
||||||
|
5. Keep docs updated
|
||||||
|
6. Use markdown
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* Manages device operations.
|
||||||
|
* @class
|
||||||
|
*/
|
||||||
|
class DeviceManager {
|
||||||
|
/**
|
||||||
|
* Gets the current state of a device.
|
||||||
|
* @param {string} deviceId - The device identifier.
|
||||||
|
* @returns {Promise<DeviceState>} The current device state.
|
||||||
|
* @throws {DeviceError} If device is not found or unavailable.
|
||||||
|
* @example
|
||||||
|
* const state = await deviceManager.getDeviceState('living_room_light');
|
||||||
|
*/
|
||||||
|
async getDeviceState(deviceId: string): Promise<DeviceState> {
|
||||||
|
// Implementation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Logging
|
||||||
|
|
||||||
|
### Best Practices
|
||||||
|
|
||||||
|
1. Use appropriate levels
|
||||||
|
2. Include context
|
||||||
|
3. Structure log data
|
||||||
|
4. Handle sensitive data
|
||||||
|
5. Implement rotation
|
||||||
|
6. Use correlation IDs
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
class Logger {
|
||||||
|
info(message: string, context: Record<string, any>) {
|
||||||
|
console.log(JSON.stringify({
|
||||||
|
level: 'info',
|
||||||
|
message,
|
||||||
|
context,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
correlationId: context.correlationId
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Version Control
|
||||||
|
|
||||||
|
### Guidelines
|
||||||
|
|
||||||
|
1. Use meaningful commits
|
||||||
|
2. Follow branching strategy
|
||||||
|
3. Write good PR descriptions
|
||||||
|
4. Review code thoroughly
|
||||||
|
5. Keep changes focused
|
||||||
|
6. Use conventional commits
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Good commit messages
|
||||||
|
git commit -m "feat(device): add support for zigbee devices"
|
||||||
|
git commit -m "fix(api): handle timeout errors properly"
|
||||||
|
```
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [Tool Development Guide](tools.md)
|
||||||
|
- [Interface Documentation](interfaces.md)
|
||||||
|
- [Testing Guide](../testing.md)
|
||||||
296
docs/development/interfaces.md
Normal file
296
docs/development/interfaces.md
Normal file
@@ -0,0 +1,296 @@
|
|||||||
|
# Interface Documentation
|
||||||
|
|
||||||
|
This document describes the core interfaces used throughout the Home Assistant MCP.
|
||||||
|
|
||||||
|
## Core Interfaces
|
||||||
|
|
||||||
|
### Tool Interface
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface Tool {
|
||||||
|
/** Unique identifier for the tool */
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
/** Human-readable name */
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
/** Detailed description */
|
||||||
|
description: string;
|
||||||
|
|
||||||
|
/** Semantic version */
|
||||||
|
version: string;
|
||||||
|
|
||||||
|
/** Tool category */
|
||||||
|
category: ToolCategory;
|
||||||
|
|
||||||
|
/** Execute tool functionality */
|
||||||
|
execute(params: any): Promise<ToolResult>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tool Result
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface ToolResult {
|
||||||
|
/** Operation success status */
|
||||||
|
success: boolean;
|
||||||
|
|
||||||
|
/** Response data */
|
||||||
|
data?: any;
|
||||||
|
|
||||||
|
/** Error message if failed */
|
||||||
|
message?: string;
|
||||||
|
|
||||||
|
/** Error code if failed */
|
||||||
|
error_code?: string;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tool Category
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
enum ToolCategory {
|
||||||
|
DeviceManagement = 'device_management',
|
||||||
|
HistoryState = 'history_state',
|
||||||
|
Automation = 'automation',
|
||||||
|
AddonsPackages = 'addons_packages',
|
||||||
|
Notifications = 'notifications',
|
||||||
|
Events = 'events',
|
||||||
|
Utility = 'utility'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Event Interfaces
|
||||||
|
|
||||||
|
### Event Subscription
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface EventSubscription {
|
||||||
|
/** Unique subscription ID */
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
/** Event type to subscribe to */
|
||||||
|
event_type: string;
|
||||||
|
|
||||||
|
/** Optional entity ID filter */
|
||||||
|
entity_id?: string;
|
||||||
|
|
||||||
|
/** Optional domain filter */
|
||||||
|
domain?: string;
|
||||||
|
|
||||||
|
/** Subscription creation timestamp */
|
||||||
|
created_at: string;
|
||||||
|
|
||||||
|
/** Last event timestamp */
|
||||||
|
last_event?: string;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Event Message
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface EventMessage {
|
||||||
|
/** Event type */
|
||||||
|
event_type: string;
|
||||||
|
|
||||||
|
/** Entity ID if applicable */
|
||||||
|
entity_id?: string;
|
||||||
|
|
||||||
|
/** Event data */
|
||||||
|
data: any;
|
||||||
|
|
||||||
|
/** Event origin */
|
||||||
|
origin: 'LOCAL' | 'REMOTE';
|
||||||
|
|
||||||
|
/** Event timestamp */
|
||||||
|
time_fired: string;
|
||||||
|
|
||||||
|
/** Event context */
|
||||||
|
context: EventContext;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Device Interfaces
|
||||||
|
|
||||||
|
### Device
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface Device {
|
||||||
|
/** Device ID */
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
/** Device name */
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
/** Device domain */
|
||||||
|
domain: string;
|
||||||
|
|
||||||
|
/** Current state */
|
||||||
|
state: string;
|
||||||
|
|
||||||
|
/** Device attributes */
|
||||||
|
attributes: Record<string, any>;
|
||||||
|
|
||||||
|
/** Device capabilities */
|
||||||
|
capabilities: DeviceCapabilities;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Device Capabilities
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface DeviceCapabilities {
|
||||||
|
/** Supported features */
|
||||||
|
features: string[];
|
||||||
|
|
||||||
|
/** Supported commands */
|
||||||
|
commands: string[];
|
||||||
|
|
||||||
|
/** State attributes */
|
||||||
|
attributes: {
|
||||||
|
/** Attribute name */
|
||||||
|
[key: string]: {
|
||||||
|
/** Attribute type */
|
||||||
|
type: 'string' | 'number' | 'boolean' | 'object';
|
||||||
|
/** Attribute description */
|
||||||
|
description: string;
|
||||||
|
/** Optional value constraints */
|
||||||
|
constraints?: {
|
||||||
|
min?: number;
|
||||||
|
max?: number;
|
||||||
|
enum?: any[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Authentication Interfaces
|
||||||
|
|
||||||
|
### Auth Token
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface AuthToken {
|
||||||
|
/** Token value */
|
||||||
|
token: string;
|
||||||
|
|
||||||
|
/** Token type */
|
||||||
|
type: 'bearer' | 'jwt';
|
||||||
|
|
||||||
|
/** Expiration timestamp */
|
||||||
|
expires_at: string;
|
||||||
|
|
||||||
|
/** Token refresh info */
|
||||||
|
refresh?: {
|
||||||
|
token: string;
|
||||||
|
expires_at: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### User
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface User {
|
||||||
|
/** User ID */
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
/** Username */
|
||||||
|
username: string;
|
||||||
|
|
||||||
|
/** User type */
|
||||||
|
type: 'admin' | 'user' | 'service';
|
||||||
|
|
||||||
|
/** User permissions */
|
||||||
|
permissions: string[];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Interfaces
|
||||||
|
|
||||||
|
### Tool Error
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface ToolError extends Error {
|
||||||
|
/** Error code */
|
||||||
|
code: string;
|
||||||
|
|
||||||
|
/** HTTP status code */
|
||||||
|
status: number;
|
||||||
|
|
||||||
|
/** Error details */
|
||||||
|
details?: Record<string, any>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Validation Error
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface ValidationError {
|
||||||
|
/** Error path */
|
||||||
|
path: string;
|
||||||
|
|
||||||
|
/** Error message */
|
||||||
|
message: string;
|
||||||
|
|
||||||
|
/** Error code */
|
||||||
|
code: string;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration Interfaces
|
||||||
|
|
||||||
|
### Tool Configuration
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface ToolConfig {
|
||||||
|
/** Enable/disable tool */
|
||||||
|
enabled: boolean;
|
||||||
|
|
||||||
|
/** Tool-specific settings */
|
||||||
|
settings: Record<string, any>;
|
||||||
|
|
||||||
|
/** Rate limiting */
|
||||||
|
rate_limit?: {
|
||||||
|
/** Max requests */
|
||||||
|
max: number;
|
||||||
|
/** Time window in seconds */
|
||||||
|
window: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### System Configuration
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface SystemConfig {
|
||||||
|
/** System name */
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
/** Environment */
|
||||||
|
environment: 'development' | 'production';
|
||||||
|
|
||||||
|
/** Log level */
|
||||||
|
log_level: 'debug' | 'info' | 'warn' | 'error';
|
||||||
|
|
||||||
|
/** Tool configurations */
|
||||||
|
tools: Record<string, ToolConfig>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. Use TypeScript for all interfaces
|
||||||
|
2. Include JSDoc comments
|
||||||
|
3. Use strict typing
|
||||||
|
4. Keep interfaces focused
|
||||||
|
5. Use consistent naming
|
||||||
|
6. Document constraints
|
||||||
|
7. Version interfaces
|
||||||
|
8. Include examples
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [Tool Development Guide](tools.md)
|
||||||
|
- [Best Practices](best-practices.md)
|
||||||
|
- [Testing Guide](../testing.md)
|
||||||
226
docs/development/tools.md
Normal file
226
docs/development/tools.md
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
# Tool Development Guide
|
||||||
|
|
||||||
|
This guide explains how to create new tools for the Home Assistant MCP.
|
||||||
|
|
||||||
|
## Tool Structure
|
||||||
|
|
||||||
|
Each tool should follow this basic structure:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface Tool {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
version: string;
|
||||||
|
category: ToolCategory;
|
||||||
|
execute(params: any): Promise<ToolResult>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Creating a New Tool
|
||||||
|
|
||||||
|
1. Create a new file in the appropriate category directory
|
||||||
|
2. Implement the Tool interface
|
||||||
|
3. Add API endpoints
|
||||||
|
4. Add WebSocket handlers
|
||||||
|
5. Add documentation
|
||||||
|
6. Add tests
|
||||||
|
|
||||||
|
### Example Tool Implementation
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { Tool, ToolCategory, ToolResult } from '../interfaces';
|
||||||
|
|
||||||
|
export class MyCustomTool implements Tool {
|
||||||
|
id = 'my_custom_tool';
|
||||||
|
name = 'My Custom Tool';
|
||||||
|
description = 'Description of what the tool does';
|
||||||
|
version = '1.0.0';
|
||||||
|
category = ToolCategory.Utility;
|
||||||
|
|
||||||
|
async execute(params: any): Promise<ToolResult> {
|
||||||
|
// Tool implementation
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
// Tool-specific response data
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tool Categories
|
||||||
|
|
||||||
|
- Device Management
|
||||||
|
- History & State
|
||||||
|
- Automation
|
||||||
|
- Add-ons & Packages
|
||||||
|
- Notifications
|
||||||
|
- Events
|
||||||
|
- Utility
|
||||||
|
|
||||||
|
## API Integration
|
||||||
|
|
||||||
|
### REST Endpoint
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { Router } from 'express';
|
||||||
|
import { MyCustomTool } from './my-custom-tool';
|
||||||
|
|
||||||
|
const router = Router();
|
||||||
|
const tool = new MyCustomTool();
|
||||||
|
|
||||||
|
router.post('/api/tools/custom', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const result = await tool.execute(req.body);
|
||||||
|
res.json(result);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### WebSocket Handler
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { WebSocketServer } from 'ws';
|
||||||
|
import { MyCustomTool } from './my-custom-tool';
|
||||||
|
|
||||||
|
const tool = new MyCustomTool();
|
||||||
|
|
||||||
|
wss.on('connection', (ws) => {
|
||||||
|
ws.on('message', async (message) => {
|
||||||
|
const { type, params } = JSON.parse(message);
|
||||||
|
if (type === 'my_custom_tool') {
|
||||||
|
const result = await tool.execute(params);
|
||||||
|
ws.send(JSON.stringify(result));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
class ToolError extends Error {
|
||||||
|
constructor(
|
||||||
|
message: string,
|
||||||
|
public code: string,
|
||||||
|
public status: number = 500
|
||||||
|
) {
|
||||||
|
super(message);
|
||||||
|
this.name = 'ToolError';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usage in tool
|
||||||
|
async execute(params: any): Promise<ToolResult> {
|
||||||
|
try {
|
||||||
|
// Tool implementation
|
||||||
|
} catch (error) {
|
||||||
|
throw new ToolError(
|
||||||
|
'Operation failed',
|
||||||
|
'TOOL_ERROR',
|
||||||
|
500
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { MyCustomTool } from './my-custom-tool';
|
||||||
|
|
||||||
|
describe('MyCustomTool', () => {
|
||||||
|
let tool: MyCustomTool;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
tool = new MyCustomTool();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should execute successfully', async () => {
|
||||||
|
const result = await tool.execute({
|
||||||
|
// Test parameters
|
||||||
|
});
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle errors', async () => {
|
||||||
|
// Error test cases
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
1. Create tool documentation in `docs/tools/category/tool-name.md`
|
||||||
|
2. Update `tools/tools.md` with tool reference
|
||||||
|
3. Add tool to navigation in `mkdocs.yml`
|
||||||
|
|
||||||
|
### Documentation Template
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# Tool Name
|
||||||
|
|
||||||
|
Description of the tool.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Feature 1
|
||||||
|
- Feature 2
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### REST API
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// API endpoints
|
||||||
|
```
|
||||||
|
|
||||||
|
### WebSocket
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// WebSocket usage
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Example 1
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Usage example
|
||||||
|
```
|
||||||
|
|
||||||
|
## Response Format
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
// Response data structure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. Follow consistent naming conventions
|
||||||
|
2. Implement proper error handling
|
||||||
|
3. Add comprehensive documentation
|
||||||
|
4. Write thorough tests
|
||||||
|
5. Use TypeScript for type safety
|
||||||
|
6. Follow SOLID principles
|
||||||
|
7. Implement rate limiting
|
||||||
|
8. Add proper logging
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [Interface Documentation](interfaces.md)
|
||||||
|
- [Best Practices](best-practices.md)
|
||||||
|
- [Testing Guide](../testing.md)
|
||||||
22
docs/examples/index.md
Normal file
22
docs/examples/index.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
layout: default
|
||||||
|
title: Examples
|
||||||
|
nav_order: 7
|
||||||
|
has_children: true
|
||||||
|
---
|
||||||
|
|
||||||
|
# Example Projects 📚
|
||||||
|
|
||||||
|
This section contains examples and tutorials for common MCP Server integrations.
|
||||||
|
|
||||||
|
## Speech-to-Text Integration
|
||||||
|
|
||||||
|
Example of integrating speech recognition with MCP Server:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// From examples/speech-to-text-example.ts
|
||||||
|
// Add example code and explanation
|
||||||
|
```
|
||||||
|
|
||||||
|
## More Examples Coming Soon
|
||||||
|
...
|
||||||
@@ -5,7 +5,7 @@ Begin your journey with the Home Assistant MCP Server by following these steps:
|
|||||||
- **API Documentation:** Read the [API Documentation](api.md) for available endpoints.
|
- **API Documentation:** Read the [API Documentation](api.md) for available endpoints.
|
||||||
- **Real-Time Updates:** Learn about [Server-Sent Events](sse-api.md) for live communication.
|
- **Real-Time Updates:** Learn about [Server-Sent Events](sse-api.md) for live communication.
|
||||||
- **Tools:** Explore available [Tools](tools/tools.md) for device control and automation.
|
- **Tools:** Explore available [Tools](tools/tools.md) for device control and automation.
|
||||||
- **Configuration:** Refer to the [Configuration Guide](configuration.md) for setup and advanced settings.
|
- **Configuration:** Refer to the [Configuration Guide](getting-started/configuration.md) for setup and advanced settings.
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
|||||||
10
docs/getting-started/docker.md
Normal file
10
docs/getting-started/docker.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
layout: default
|
||||||
|
title: Docker Deployment
|
||||||
|
parent: Getting Started
|
||||||
|
nav_order: 3
|
||||||
|
---
|
||||||
|
|
||||||
|
# Docker Deployment Guide 🐳
|
||||||
|
|
||||||
|
Detailed guide for deploying MCP Server with Docker...
|
||||||
@@ -1,124 +1,181 @@
|
|||||||
# Installation Guide
|
---
|
||||||
|
layout: default
|
||||||
|
title: Installation
|
||||||
|
parent: Getting Started
|
||||||
|
nav_order: 1
|
||||||
|
---
|
||||||
|
|
||||||
|
# Installation Guide 🛠️
|
||||||
|
|
||||||
|
This guide covers different methods to install and set up the MCP Server for Home Assistant. Choose the installation method that best suits your needs.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
### System Requirements
|
Before installing MCP Server, ensure you have:
|
||||||
- **Operating System:** Linux, macOS, or Windows (Docker recommended)
|
|
||||||
- **Runtime:** Bun v1.0.26 or higher
|
|
||||||
- **Home Assistant:** v2023.11 or higher
|
|
||||||
- **Minimum Hardware:**
|
|
||||||
- 2 CPU cores
|
|
||||||
- 2GB RAM
|
|
||||||
- 10GB free disk space
|
|
||||||
|
|
||||||
### Software Dependencies
|
- Home Assistant instance running and accessible
|
||||||
- Bun runtime
|
- Node.js 18+ or Docker installed
|
||||||
- Docker (optional, recommended for deployment)
|
- Home Assistant Long-Lived Access Token ([How to get one](https://developers.home-assistant.io/docs/auth_api/#long-lived-access-token))
|
||||||
- Git
|
|
||||||
- Node.js (for some development tasks)
|
|
||||||
|
|
||||||
## Installation Methods
|
## Installation Methods
|
||||||
|
|
||||||
### 1. Basic Setup
|
### 1. 🔧 Smithery Installation (Recommended)
|
||||||
|
|
||||||
#### Install Bun
|
The easiest way to install MCP Server is through Smithery:
|
||||||
```bash
|
|
||||||
curl -fsSL https://bun.sh/install | bash
|
#### Smithery Configuration
|
||||||
|
|
||||||
|
The project includes a `smithery.yaml` configuration:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Add smithery.yaml contents and explanation
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Clone Repository
|
#### Installation Steps
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/jango-blockchained/homeassistant-mcp.git
|
npx -y @smithery/cli install @jango-blockchained/advanced-homeassistant-mcp --client claude
|
||||||
cd homeassistant-mcp
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Install Dependencies
|
### 2. 🐳 Docker Installation
|
||||||
```bash
|
|
||||||
bun install
|
For a containerized deployment:
|
||||||
```
|
|
||||||
|
|
||||||
#### Configure Environment
|
|
||||||
1. Copy environment template
|
|
||||||
```bash
|
```bash
|
||||||
|
# Clone the repository
|
||||||
|
git clone --depth 1 https://github.com/jango-blockchained/advanced-homeassistant-mcp.git
|
||||||
|
cd advanced-homeassistant-mcp
|
||||||
|
|
||||||
|
# Configure environment variables
|
||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
```
|
# Edit .env with your Home Assistant details:
|
||||||
2. Edit `.env` file with your Home Assistant configuration
|
# - HA_URL: Your Home Assistant URL
|
||||||
- Set `HASS_HOST`
|
# - HA_TOKEN: Your Long-Lived Access Token
|
||||||
- Configure authentication tokens
|
# - Other configuration options
|
||||||
- Adjust other settings as needed
|
|
||||||
|
|
||||||
#### Build and Start
|
# Build and start containers
|
||||||
```bash
|
docker compose up -d --build
|
||||||
bun run build
|
|
||||||
bun start
|
# View logs (optional)
|
||||||
|
docker compose logs -f --tail=50
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Docker Setup (Recommended)
|
### 3. 💻 Manual Installation
|
||||||
|
|
||||||
#### Prerequisites
|
For direct installation on your system:
|
||||||
- Docker
|
|
||||||
- Docker Compose
|
|
||||||
|
|
||||||
#### Deployment Steps
|
|
||||||
```bash
|
```bash
|
||||||
# Clone repository
|
# Install Bun runtime
|
||||||
git clone https://github.com/jango-blockchained/homeassistant-mcp.git
|
curl -fsSL https://bun.sh/install | bash
|
||||||
cd homeassistant-mcp
|
|
||||||
|
# Clone and install
|
||||||
|
git clone https://github.com/jango-blockchained/advanced-homeassistant-mcp.git
|
||||||
|
cd advanced-homeassistant-mcp
|
||||||
|
bun install --frozen-lockfile
|
||||||
|
|
||||||
# Configure environment
|
# Configure environment
|
||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
# Edit .env file with your settings
|
# Edit .env with your configuration
|
||||||
|
|
||||||
# Deploy with Docker Compose
|
# Start the server
|
||||||
docker compose up -d
|
bun run dev --watch
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Home Assistant Add-on (Coming Soon)
|
## Configuration
|
||||||
We're working on a direct Home Assistant add-on for even easier installation.
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
Key configuration options in your `.env` file:
|
||||||
|
|
||||||
|
```env
|
||||||
|
# Home Assistant Configuration
|
||||||
|
HA_URL=http://your-homeassistant:8123
|
||||||
|
HA_TOKEN=your_long_lived_access_token
|
||||||
|
|
||||||
|
# Server Configuration
|
||||||
|
PORT=3000
|
||||||
|
HOST=0.0.0.0
|
||||||
|
NODE_ENV=production
|
||||||
|
|
||||||
|
# Security Settings
|
||||||
|
JWT_SECRET=your_secure_jwt_secret
|
||||||
|
RATE_LIMIT=100
|
||||||
|
```
|
||||||
|
|
||||||
|
### Client Integration
|
||||||
|
|
||||||
|
#### Cursor Integration
|
||||||
|
|
||||||
|
Add to `.cursor/config/config.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"homeassistant-mcp": {
|
||||||
|
"command": "bun",
|
||||||
|
"args": ["run", "start"],
|
||||||
|
"cwd": "${workspaceRoot}",
|
||||||
|
"env": {
|
||||||
|
"NODE_ENV": "development"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Claude Desktop Integration
|
||||||
|
|
||||||
|
Add to your Claude configuration:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"homeassistant-mcp": {
|
||||||
|
"command": "bun",
|
||||||
|
"args": ["run", "start", "--port", "8080"],
|
||||||
|
"env": {
|
||||||
|
"NODE_ENV": "production"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|
||||||
### Check Installation
|
To verify your installation:
|
||||||
- Web Interface: [http://localhost:3000](http://localhost:3000)
|
|
||||||
- Logs: `docker compose logs` or check `logs/` directory
|
|
||||||
|
|
||||||
### Troubleshooting
|
1. Check server status:
|
||||||
- Ensure all environment variables are correctly set
|
```bash
|
||||||
- Check network connectivity to Home Assistant
|
curl http://localhost:3000/health
|
||||||
- Verify authentication tokens
|
```
|
||||||
|
|
||||||
## Updating
|
2. Test Home Assistant connection:
|
||||||
|
```bash
|
||||||
|
curl http://localhost:3000/api/state
|
||||||
|
```
|
||||||
|
|
||||||
### Basic Setup
|
## Troubleshooting
|
||||||
```bash
|
|
||||||
git pull
|
|
||||||
bun install
|
|
||||||
bun run build
|
|
||||||
bun start
|
|
||||||
```
|
|
||||||
|
|
||||||
### Docker
|
If you encounter issues:
|
||||||
```bash
|
|
||||||
git pull
|
|
||||||
docker compose up -d --build
|
|
||||||
```
|
|
||||||
|
|
||||||
## Uninstallation
|
1. Check the [Troubleshooting Guide](../troubleshooting.md)
|
||||||
|
2. Verify your environment variables
|
||||||
|
3. Check server logs:
|
||||||
|
```bash
|
||||||
|
# For Docker installation
|
||||||
|
docker compose logs -f
|
||||||
|
|
||||||
### Basic Setup
|
# For manual installation
|
||||||
```bash
|
bun run dev
|
||||||
cd homeassistant-mcp
|
```
|
||||||
bun stop # Stop the application
|
|
||||||
rm -rf node_modules dist
|
|
||||||
```
|
|
||||||
|
|
||||||
### Docker
|
|
||||||
```bash
|
|
||||||
docker compose down
|
|
||||||
docker rmi homeassistant-mcp # Remove image
|
|
||||||
```
|
|
||||||
|
|
||||||
## Next Steps
|
## Next Steps
|
||||||
- [Configuration Guide](configuration.md)
|
|
||||||
- [Usage Instructions](../usage.md)
|
- Follow the [Quick Start Guide](quickstart.md) to begin using MCP Server
|
||||||
- [Troubleshooting](../troubleshooting.md)
|
- Read the [API Documentation](../api/index.md) for integration details
|
||||||
|
- Check the [Architecture Overview](../architecture.md) to understand the system
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
Need help? Check our [Support Resources](../index.md#support) or [open an issue](https://github.com/jango-blockchained/advanced-homeassistant-mcp/issues).
|
||||||
219
docs/getting-started/quickstart.md
Normal file
219
docs/getting-started/quickstart.md
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
---
|
||||||
|
layout: default
|
||||||
|
title: Quick Start
|
||||||
|
parent: Getting Started
|
||||||
|
nav_order: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
# Quick Start Guide 🚀
|
||||||
|
|
||||||
|
This guide will help you get started with MCP Server after installation. We'll cover basic usage, common commands, and simple integrations.
|
||||||
|
|
||||||
|
## First Steps
|
||||||
|
|
||||||
|
### 1. Verify Connection
|
||||||
|
|
||||||
|
After installation, verify your MCP Server is running and connected to Home Assistant:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check server health
|
||||||
|
curl http://localhost:3000/health
|
||||||
|
|
||||||
|
# Verify Home Assistant connection
|
||||||
|
curl http://localhost:3000/api/state
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Basic Voice Commands
|
||||||
|
|
||||||
|
Try these basic voice commands to test your setup:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Example using curl for testing
|
||||||
|
curl -X POST http://localhost:3000/api/command \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"command": "Turn on the living room lights"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Common voice commands:
|
||||||
|
- "Turn on/off [device name]"
|
||||||
|
- "Set [device] to [value]"
|
||||||
|
- "What's the temperature in [room]?"
|
||||||
|
- "Is [device] on or off?"
|
||||||
|
|
||||||
|
## Real-World Examples
|
||||||
|
|
||||||
|
### 1. Smart Lighting Control
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Browser example using fetch
|
||||||
|
const response = await fetch('http://localhost:3000/api/command', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
command: 'Set living room lights to 50% brightness and warm white color'
|
||||||
|
})
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Real-Time Updates
|
||||||
|
|
||||||
|
Subscribe to device state changes using Server-Sent Events (SSE):
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const eventSource = new EventSource('http://localhost:3000/subscribe_events?token=YOUR_TOKEN&domain=light');
|
||||||
|
|
||||||
|
eventSource.onmessage = (event) => {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
console.log('Device state changed:', data);
|
||||||
|
// Update your UI here
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Scene Automation
|
||||||
|
|
||||||
|
Create and trigger scenes for different activities:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Create a "Movie Night" scene
|
||||||
|
const createScene = async () => {
|
||||||
|
await fetch('http://localhost:3000/api/scene', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
name: 'Movie Night',
|
||||||
|
actions: [
|
||||||
|
{ device: 'living_room_lights', action: 'dim', value: 20 },
|
||||||
|
{ device: 'tv', action: 'on' },
|
||||||
|
{ device: 'soundbar', action: 'on' }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Trigger the scene with voice command:
|
||||||
|
// "Hey MCP, activate movie night scene"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Integration Examples
|
||||||
|
|
||||||
|
### 1. Web Dashboard Integration
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// React component example
|
||||||
|
function SmartHomeControl() {
|
||||||
|
const [devices, setDevices] = useState([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Subscribe to device updates
|
||||||
|
const events = new EventSource('http://localhost:3000/subscribe_events');
|
||||||
|
events.onmessage = (event) => {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
setDevices(currentDevices =>
|
||||||
|
currentDevices.map(device =>
|
||||||
|
device.id === data.id ? {...device, ...data} : device
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return () => events.close();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="dashboard">
|
||||||
|
{devices.map(device => (
|
||||||
|
<DeviceCard key={device.id} device={device} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Voice Assistant Integration
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Example using speech-to-text with MCP
|
||||||
|
async function handleVoiceCommand(audioBlob: Blob) {
|
||||||
|
// First, convert speech to text
|
||||||
|
const text = await speechToText(audioBlob);
|
||||||
|
|
||||||
|
// Then send command to MCP
|
||||||
|
const response = await fetch('http://localhost:3000/api/command', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ command: text })
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Error Handling**
|
||||||
|
```javascript
|
||||||
|
try {
|
||||||
|
const response = await fetch('http://localhost:3000/api/command', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ command: 'Turn on lights' })
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error);
|
||||||
|
// Handle error appropriately
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Connection Management**
|
||||||
|
```javascript
|
||||||
|
class MCPConnection {
|
||||||
|
constructor() {
|
||||||
|
this.eventSource = null;
|
||||||
|
this.reconnectAttempts = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
this.eventSource = new EventSource('http://localhost:3000/subscribe_events');
|
||||||
|
this.eventSource.onerror = this.handleError.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleError() {
|
||||||
|
if (this.reconnectAttempts < 3) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.reconnectAttempts++;
|
||||||
|
this.connect();
|
||||||
|
}, 1000 * this.reconnectAttempts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- Explore the [API Documentation](../api/index.md) for advanced features
|
||||||
|
- Learn about [SSE API](../api/sse.md) for real-time updates
|
||||||
|
- Check out [Architecture](../architecture.md) for system design details
|
||||||
|
- Read the [Contributing Guide](../contributing.md) to get involved
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
If you encounter issues:
|
||||||
|
- Verify your authentication token
|
||||||
|
- Check server logs for errors
|
||||||
|
- Ensure Home Assistant is accessible
|
||||||
|
- Review the [Troubleshooting Guide](../troubleshooting.md)
|
||||||
|
|
||||||
|
Need more help? Visit our [Support Resources](../index.md#support).
|
||||||
119
docs/index.md
119
docs/index.md
@@ -4,107 +4,52 @@ title: Home
|
|||||||
nav_order: 1
|
nav_order: 1
|
||||||
---
|
---
|
||||||
|
|
||||||
# 📚 Home Assistant MCP Documentation
|
# 🚀 MCP Server for Home Assistant
|
||||||
|
|
||||||
Welcome to the documentation for the Home Assistant MCP (Model Context Protocol) Server.
|
Welcome to the Model Context Protocol (MCP) Server documentation! This guide will help you get started with integrating AI-powered natural language processing into your Home Assistant setup.
|
||||||
|
|
||||||
## 📑 Documentation Index
|
## What is MCP Server?
|
||||||
|
|
||||||
- [Getting Started Guide](getting-started.md)
|
MCP Server is a bridge between Home Assistant and Language Learning Models (LLMs), enabling natural language interactions and real-time automation of your smart devices. It allows you to control your home automation setup using natural language commands while maintaining high performance and security.
|
||||||
- [API Documentation](api.md)
|
|
||||||
- [Troubleshooting](troubleshooting.md)
|
|
||||||
- [Contributing Guide](contributing.md)
|
|
||||||
|
|
||||||
For project overview, installation, and general information, please see our [main README](../README.md).
|
|
||||||
|
|
||||||
## 🔗 Quick Links
|
|
||||||
|
|
||||||
- [GitHub Repository](https://github.com/jango-blockchained/homeassistant-mcp)
|
|
||||||
- [Issue Tracker](https://github.com/jango-blockchained/homeassistant-mcp/issues)
|
|
||||||
- [GitHub Discussions](https://github.com/jango-blockchained/homeassistant-mcp/discussions)
|
|
||||||
|
|
||||||
## 📝 License
|
|
||||||
|
|
||||||
This project is licensed under the MIT License. See [LICENSE](../LICENSE) for details.
|
|
||||||
|
|
||||||
# Model Context Protocol (MCP) Server
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
The Model Context Protocol (MCP) Server is a cutting-edge bridge between Home Assistant and Language Learning Models (LLMs), designed to revolutionize smart home automation and control. This documentation provides comprehensive information about setting up, configuring, and using the Home Assistant MCP.
|
|
||||||
|
|
||||||
## Key Features
|
## Key Features
|
||||||
|
|
||||||
### 🏠 Smart Home Integration
|
### 🎮 Device Control & Monitoring
|
||||||
- Natural language control of smart devices
|
- Voice-controlled automation
|
||||||
- Real-time device state monitoring
|
- Real-time updates via SSE/WebSocket
|
||||||
- Advanced automation capabilities
|
- Scene-based automation rules
|
||||||
|
|
||||||
### 🤖 LLM Powered Interactions
|
### 🤖 AI-Powered Features
|
||||||
- Intuitive voice and text-based commands
|
- Natural Language Processing (NLP)
|
||||||
- Context-aware device management
|
- Predictive automation
|
||||||
- Intelligent automation suggestions
|
- Anomaly detection
|
||||||
|
|
||||||
### 🔒 Security & Performance
|
### 🛡️ Security & Performance
|
||||||
- Token-based authentication
|
- JWT authentication
|
||||||
- High-performance Bun runtime
|
- Request sanitization
|
||||||
- Secure, real-time communication protocols
|
- Sub-100ms latency
|
||||||
|
- Rate limiting
|
||||||
|
|
||||||
## Documentation
|
## Documentation Structure
|
||||||
|
|
||||||
|
### Getting Started
|
||||||
|
- [Installation Guide](getting-started/installation.md) - Set up MCP Server
|
||||||
|
- [Quick Start Tutorial](getting-started/quickstart.md) - Basic usage examples
|
||||||
|
|
||||||
### Core Documentation
|
### Core Documentation
|
||||||
1. [Getting Started](getting-started.md)
|
- [API Documentation](api/index.md) - Complete API reference
|
||||||
- Installation and basic setup
|
- [Architecture Overview](architecture.md) - System design and components
|
||||||
- Configuration
|
- [Contributing Guidelines](contributing.md) - How to contribute
|
||||||
- First Steps
|
- [Troubleshooting Guide](troubleshooting.md) - Common issues and solutions
|
||||||
|
|
||||||
2. [API Reference](api.md)
|
## Support
|
||||||
- REST API Endpoints
|
|
||||||
- Authentication
|
|
||||||
- Error Handling
|
|
||||||
|
|
||||||
3. [SSE API](sse-api.md)
|
If you need help or want to report issues:
|
||||||
- Event Subscriptions
|
|
||||||
- Real-time Updates
|
|
||||||
- Connection Management
|
|
||||||
|
|
||||||
### Advanced Topics
|
- [GitHub Issues](https://github.com/jango-blockchained/advanced-homeassistant-mcp/issues)
|
||||||
4. [Architecture](architecture.md)
|
- [GitHub Discussions](https://github.com/jango-blockchained/advanced-homeassistant-mcp/discussions)
|
||||||
- System Design
|
- [Contributing Guidelines](contributing.md)
|
||||||
- Components
|
|
||||||
- Data Flow
|
|
||||||
|
|
||||||
5. [Configuration](getting-started.md#configuration)
|
|
||||||
- Environment Variables
|
|
||||||
- Security Settings
|
|
||||||
- Performance Tuning
|
|
||||||
|
|
||||||
6. [Development Guide](development/development.md)
|
|
||||||
- Project Structure
|
|
||||||
- Contributing Guidelines
|
|
||||||
- Testing
|
|
||||||
|
|
||||||
7. [Troubleshooting](troubleshooting.md)
|
|
||||||
- Common Issues
|
|
||||||
- Debugging
|
|
||||||
- FAQ
|
|
||||||
|
|
||||||
## Quick Links
|
|
||||||
|
|
||||||
- [GitHub Repository](https://github.com/jango-blockchained/homeassistant-mcp)
|
|
||||||
- [Issue Tracker](https://github.com/jango-blockchained/homeassistant-mcp/issues)
|
|
||||||
- [Contributing Guide](contributing.md)
|
|
||||||
- [Roadmap](roadmap.md)
|
|
||||||
|
|
||||||
## Community and Support
|
|
||||||
|
|
||||||
If you need help or have questions:
|
|
||||||
|
|
||||||
1. Check the [Troubleshooting Guide](troubleshooting.md)
|
|
||||||
2. Search existing [Issues](https://github.com/jango-blockchained/homeassistant-mcp/issues)
|
|
||||||
3. Join our [GitHub Discussions](https://github.com/jango-blockchained/homeassistant-mcp/discussions)
|
|
||||||
4. Create a new issue if your problem isn't already reported
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This project is licensed under the MIT License. See [LICENSE](https://github.com/jango-blockchained/homeassistant-mcp/blob/main/LICENSE) for details.
|
This project is licensed under the MIT License. See the [LICENSE](https://github.com/jango-blockchained/advanced-homeassistant-mcp/blob/main/LICENSE) file for details.
|
||||||
240
docs/tools/addons-packages/addon.md
Normal file
240
docs/tools/addons-packages/addon.md
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
# Add-on Management Tool
|
||||||
|
|
||||||
|
The Add-on Management tool provides functionality to manage Home Assistant add-ons through the MCP interface.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- List available add-ons
|
||||||
|
- Install/uninstall add-ons
|
||||||
|
- Start/stop/restart add-ons
|
||||||
|
- Get add-on information
|
||||||
|
- Update add-ons
|
||||||
|
- Configure add-ons
|
||||||
|
- View add-on logs
|
||||||
|
- Monitor add-on status
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### REST API
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
GET /api/addons
|
||||||
|
GET /api/addons/{addon_slug}
|
||||||
|
POST /api/addons/{addon_slug}/install
|
||||||
|
POST /api/addons/{addon_slug}/uninstall
|
||||||
|
POST /api/addons/{addon_slug}/start
|
||||||
|
POST /api/addons/{addon_slug}/stop
|
||||||
|
POST /api/addons/{addon_slug}/restart
|
||||||
|
GET /api/addons/{addon_slug}/logs
|
||||||
|
PUT /api/addons/{addon_slug}/config
|
||||||
|
GET /api/addons/{addon_slug}/stats
|
||||||
|
```
|
||||||
|
|
||||||
|
### WebSocket
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// List add-ons
|
||||||
|
{
|
||||||
|
"type": "get_addons"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get add-on info
|
||||||
|
{
|
||||||
|
"type": "get_addon_info",
|
||||||
|
"addon_slug": "required_addon_slug"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Install add-on
|
||||||
|
{
|
||||||
|
"type": "install_addon",
|
||||||
|
"addon_slug": "required_addon_slug",
|
||||||
|
"version": "optional_version"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Control add-on
|
||||||
|
{
|
||||||
|
"type": "control_addon",
|
||||||
|
"addon_slug": "required_addon_slug",
|
||||||
|
"action": "start|stop|restart"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### List All Add-ons
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/addons', {
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const addons = await response.json();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Install Add-on
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/addons/mosquitto/install', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
"version": "latest"
|
||||||
|
})
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configure Add-on
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/addons/mosquitto/config', {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
"logins": [
|
||||||
|
{
|
||||||
|
"username": "mqtt_user",
|
||||||
|
"password": "mqtt_password"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"customize": {
|
||||||
|
"active": true,
|
||||||
|
"folder": "mosquitto"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Response Format
|
||||||
|
|
||||||
|
### Add-on List Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"addons": [
|
||||||
|
{
|
||||||
|
"slug": "addon_slug",
|
||||||
|
"name": "Add-on Name",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"state": "started",
|
||||||
|
"repository": "core",
|
||||||
|
"installed": true,
|
||||||
|
"update_available": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add-on Info Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"addon": {
|
||||||
|
"slug": "addon_slug",
|
||||||
|
"name": "Add-on Name",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Add-on description",
|
||||||
|
"long_description": "Detailed description",
|
||||||
|
"repository": "core",
|
||||||
|
"installed": true,
|
||||||
|
"state": "started",
|
||||||
|
"webui": "http://[HOST]:[PORT:80]",
|
||||||
|
"boot": "auto",
|
||||||
|
"options": {
|
||||||
|
// Add-on specific options
|
||||||
|
},
|
||||||
|
"schema": {
|
||||||
|
// Add-on options schema
|
||||||
|
},
|
||||||
|
"ports": {
|
||||||
|
"80/tcp": 8080
|
||||||
|
},
|
||||||
|
"ingress": true,
|
||||||
|
"ingress_port": 8099
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add-on Stats Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"stats": {
|
||||||
|
"cpu_percent": 2.5,
|
||||||
|
"memory_usage": 128974848,
|
||||||
|
"memory_limit": 536870912,
|
||||||
|
"network_rx": 1234,
|
||||||
|
"network_tx": 5678,
|
||||||
|
"blk_read": 12345,
|
||||||
|
"blk_write": 67890
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
### Common Error Codes
|
||||||
|
|
||||||
|
- `404`: Add-on not found
|
||||||
|
- `401`: Unauthorized
|
||||||
|
- `400`: Invalid request
|
||||||
|
- `409`: Add-on operation failed
|
||||||
|
- `422`: Invalid configuration
|
||||||
|
|
||||||
|
### Error Response Format
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": false,
|
||||||
|
"message": "Error description",
|
||||||
|
"error_code": "ERROR_CODE"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rate Limiting
|
||||||
|
|
||||||
|
- Default limit: 50 requests per 15 minutes
|
||||||
|
- Configurable through environment variables:
|
||||||
|
- `ADDON_RATE_LIMIT`
|
||||||
|
- `ADDON_RATE_WINDOW`
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. Always check add-on compatibility
|
||||||
|
2. Back up configurations before updates
|
||||||
|
3. Monitor resource usage
|
||||||
|
4. Use appropriate update strategies
|
||||||
|
5. Implement proper error handling
|
||||||
|
6. Test configurations in safe environment
|
||||||
|
7. Handle rate limiting gracefully
|
||||||
|
8. Keep add-ons updated
|
||||||
|
|
||||||
|
## Add-on Security
|
||||||
|
|
||||||
|
- Use secure passwords
|
||||||
|
- Regularly update add-ons
|
||||||
|
- Monitor add-on logs
|
||||||
|
- Restrict network access
|
||||||
|
- Use SSL/TLS when available
|
||||||
|
- Follow principle of least privilege
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [Package Management](package.md)
|
||||||
|
- [Device Control](../device-management/control.md)
|
||||||
|
- [Event Subscription](../events/subscribe-events.md)
|
||||||
236
docs/tools/addons-packages/package.md
Normal file
236
docs/tools/addons-packages/package.md
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
# Package Management Tool
|
||||||
|
|
||||||
|
The Package Management tool provides functionality to manage Home Assistant Community Store (HACS) packages through the MCP interface.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- List available packages
|
||||||
|
- Install/update/remove packages
|
||||||
|
- Search packages
|
||||||
|
- Get package information
|
||||||
|
- Manage package repositories
|
||||||
|
- Track package updates
|
||||||
|
- View package documentation
|
||||||
|
- Monitor package status
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### REST API
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
GET /api/packages
|
||||||
|
GET /api/packages/{package_id}
|
||||||
|
POST /api/packages/{package_id}/install
|
||||||
|
POST /api/packages/{package_id}/uninstall
|
||||||
|
POST /api/packages/{package_id}/update
|
||||||
|
GET /api/packages/search
|
||||||
|
GET /api/packages/categories
|
||||||
|
GET /api/packages/repositories
|
||||||
|
```
|
||||||
|
|
||||||
|
### WebSocket
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// List packages
|
||||||
|
{
|
||||||
|
"type": "get_packages",
|
||||||
|
"category": "optional_category"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search packages
|
||||||
|
{
|
||||||
|
"type": "search_packages",
|
||||||
|
"query": "search_query",
|
||||||
|
"category": "optional_category"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Install package
|
||||||
|
{
|
||||||
|
"type": "install_package",
|
||||||
|
"package_id": "required_package_id",
|
||||||
|
"version": "optional_version"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Package Categories
|
||||||
|
|
||||||
|
- Integrations
|
||||||
|
- Frontend
|
||||||
|
- Themes
|
||||||
|
- AppDaemon Apps
|
||||||
|
- NetDaemon Apps
|
||||||
|
- Python Scripts
|
||||||
|
- Plugins
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### List All Packages
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/packages', {
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const packages = await response.json();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Search Packages
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/packages/search?q=weather&category=integrations', {
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const searchResults = await response.json();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Install Package
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/packages/custom-weather-card/install', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
"version": "latest"
|
||||||
|
})
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Response Format
|
||||||
|
|
||||||
|
### Package List Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"packages": [
|
||||||
|
{
|
||||||
|
"id": "package_id",
|
||||||
|
"name": "Package Name",
|
||||||
|
"category": "integrations",
|
||||||
|
"description": "Package description",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"installed": true,
|
||||||
|
"update_available": false,
|
||||||
|
"stars": 150,
|
||||||
|
"downloads": 10000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Package Info Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"package": {
|
||||||
|
"id": "package_id",
|
||||||
|
"name": "Package Name",
|
||||||
|
"category": "integrations",
|
||||||
|
"description": "Package description",
|
||||||
|
"long_description": "Detailed description",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"installed_version": "0.9.0",
|
||||||
|
"available_version": "1.0.0",
|
||||||
|
"installed": true,
|
||||||
|
"update_available": true,
|
||||||
|
"stars": 150,
|
||||||
|
"downloads": 10000,
|
||||||
|
"repository": "https://github.com/author/repo",
|
||||||
|
"author": {
|
||||||
|
"name": "Author Name",
|
||||||
|
"url": "https://github.com/author"
|
||||||
|
},
|
||||||
|
"documentation": "https://github.com/author/repo/wiki",
|
||||||
|
"dependencies": [
|
||||||
|
"dependency1",
|
||||||
|
"dependency2"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Search Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"id": "package_id",
|
||||||
|
"name": "Package Name",
|
||||||
|
"category": "integrations",
|
||||||
|
"description": "Package description",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"score": 0.95
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total": 42
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
### Common Error Codes
|
||||||
|
|
||||||
|
- `404`: Package not found
|
||||||
|
- `401`: Unauthorized
|
||||||
|
- `400`: Invalid request
|
||||||
|
- `409`: Package operation failed
|
||||||
|
- `422`: Invalid configuration
|
||||||
|
- `424`: Dependency error
|
||||||
|
|
||||||
|
### Error Response Format
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": false,
|
||||||
|
"message": "Error description",
|
||||||
|
"error_code": "ERROR_CODE"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rate Limiting
|
||||||
|
|
||||||
|
- Default limit: 50 requests per 15 minutes
|
||||||
|
- Configurable through environment variables:
|
||||||
|
- `PACKAGE_RATE_LIMIT`
|
||||||
|
- `PACKAGE_RATE_WINDOW`
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. Check package compatibility
|
||||||
|
2. Review package documentation
|
||||||
|
3. Verify package dependencies
|
||||||
|
4. Back up before updates
|
||||||
|
5. Test in safe environment
|
||||||
|
6. Monitor resource usage
|
||||||
|
7. Keep packages updated
|
||||||
|
8. Handle rate limiting gracefully
|
||||||
|
|
||||||
|
## Package Security
|
||||||
|
|
||||||
|
- Verify package sources
|
||||||
|
- Review package permissions
|
||||||
|
- Check package reputation
|
||||||
|
- Monitor package activity
|
||||||
|
- Keep dependencies updated
|
||||||
|
- Follow security advisories
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [Add-on Management](addon.md)
|
||||||
|
- [Device Control](../device-management/control.md)
|
||||||
|
- [Event Subscription](../events/subscribe-events.md)
|
||||||
321
docs/tools/automation/automation-config.md
Normal file
321
docs/tools/automation/automation-config.md
Normal file
@@ -0,0 +1,321 @@
|
|||||||
|
# Automation Configuration Tool
|
||||||
|
|
||||||
|
The Automation Configuration tool provides functionality to create, update, and manage Home Assistant automation configurations.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Create new automations
|
||||||
|
- Update existing automations
|
||||||
|
- Delete automations
|
||||||
|
- Duplicate automations
|
||||||
|
- Import/Export automation configurations
|
||||||
|
- Validate automation configurations
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### REST API
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/automations
|
||||||
|
PUT /api/automations/{automation_id}
|
||||||
|
DELETE /api/automations/{automation_id}
|
||||||
|
POST /api/automations/{automation_id}/duplicate
|
||||||
|
POST /api/automations/validate
|
||||||
|
```
|
||||||
|
|
||||||
|
### WebSocket
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Create automation
|
||||||
|
{
|
||||||
|
"type": "create_automation",
|
||||||
|
"automation": {
|
||||||
|
// Automation configuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update automation
|
||||||
|
{
|
||||||
|
"type": "update_automation",
|
||||||
|
"automation_id": "required_automation_id",
|
||||||
|
"automation": {
|
||||||
|
// Updated configuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete automation
|
||||||
|
{
|
||||||
|
"type": "delete_automation",
|
||||||
|
"automation_id": "required_automation_id"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Automation Configuration
|
||||||
|
|
||||||
|
### Basic Structure
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "morning_routine",
|
||||||
|
"alias": "Morning Routine",
|
||||||
|
"description": "Turn on lights and adjust temperature in the morning",
|
||||||
|
"trigger": [
|
||||||
|
{
|
||||||
|
"platform": "time",
|
||||||
|
"at": "07:00:00"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"condition": [
|
||||||
|
{
|
||||||
|
"condition": "time",
|
||||||
|
"weekday": ["mon", "tue", "wed", "thu", "fri"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"action": [
|
||||||
|
{
|
||||||
|
"service": "light.turn_on",
|
||||||
|
"target": {
|
||||||
|
"entity_id": "light.bedroom"
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"brightness": 255,
|
||||||
|
"transition": 300
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mode": "single"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Trigger Types
|
||||||
|
|
||||||
|
```json
|
||||||
|
// Time-based trigger
|
||||||
|
{
|
||||||
|
"platform": "time",
|
||||||
|
"at": "07:00:00"
|
||||||
|
}
|
||||||
|
|
||||||
|
// State-based trigger
|
||||||
|
{
|
||||||
|
"platform": "state",
|
||||||
|
"entity_id": "binary_sensor.motion",
|
||||||
|
"to": "on"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event-based trigger
|
||||||
|
{
|
||||||
|
"platform": "event",
|
||||||
|
"event_type": "custom_event"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Numeric state trigger
|
||||||
|
{
|
||||||
|
"platform": "numeric_state",
|
||||||
|
"entity_id": "sensor.temperature",
|
||||||
|
"above": 25
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Condition Types
|
||||||
|
|
||||||
|
```json
|
||||||
|
// Time condition
|
||||||
|
{
|
||||||
|
"condition": "time",
|
||||||
|
"after": "07:00:00",
|
||||||
|
"before": "22:00:00"
|
||||||
|
}
|
||||||
|
|
||||||
|
// State condition
|
||||||
|
{
|
||||||
|
"condition": "state",
|
||||||
|
"entity_id": "device_tracker.phone",
|
||||||
|
"state": "home"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Numeric state condition
|
||||||
|
{
|
||||||
|
"condition": "numeric_state",
|
||||||
|
"entity_id": "sensor.temperature",
|
||||||
|
"below": 25
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Action Types
|
||||||
|
|
||||||
|
```json
|
||||||
|
// Service call action
|
||||||
|
{
|
||||||
|
"service": "light.turn_on",
|
||||||
|
"target": {
|
||||||
|
"entity_id": "light.bedroom"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delay action
|
||||||
|
{
|
||||||
|
"delay": "00:00:30"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scene activation
|
||||||
|
{
|
||||||
|
"scene": "scene.evening_mode"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conditional action
|
||||||
|
{
|
||||||
|
"choose": [
|
||||||
|
{
|
||||||
|
"conditions": [
|
||||||
|
{
|
||||||
|
"condition": "state",
|
||||||
|
"entity_id": "sun.sun",
|
||||||
|
"state": "below_horizon"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sequence": [
|
||||||
|
{
|
||||||
|
"service": "light.turn_on",
|
||||||
|
"target": {
|
||||||
|
"entity_id": "light.living_room"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Create New Automation
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/automations', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
"alias": "Morning Routine",
|
||||||
|
"description": "Turn on lights in the morning",
|
||||||
|
"trigger": [
|
||||||
|
{
|
||||||
|
"platform": "time",
|
||||||
|
"at": "07:00:00"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"action": [
|
||||||
|
{
|
||||||
|
"service": "light.turn_on",
|
||||||
|
"target": {
|
||||||
|
"entity_id": "light.bedroom"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Update Existing Automation
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/automations/morning_routine', {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
"alias": "Morning Routine",
|
||||||
|
"trigger": [
|
||||||
|
{
|
||||||
|
"platform": "time",
|
||||||
|
"at": "07:30:00" // Updated time
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"action": [
|
||||||
|
{
|
||||||
|
"service": "light.turn_on",
|
||||||
|
"target": {
|
||||||
|
"entity_id": "light.bedroom"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Response Format
|
||||||
|
|
||||||
|
### Success Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"automation": {
|
||||||
|
"id": "created_automation_id",
|
||||||
|
// Full automation configuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Validation Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"valid": true,
|
||||||
|
"warnings": [
|
||||||
|
"No conditions specified"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
### Common Error Codes
|
||||||
|
|
||||||
|
- `404`: Automation not found
|
||||||
|
- `401`: Unauthorized
|
||||||
|
- `400`: Invalid configuration
|
||||||
|
- `409`: Automation creation/update failed
|
||||||
|
|
||||||
|
### Error Response Format
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": false,
|
||||||
|
"message": "Error description",
|
||||||
|
"error_code": "ERROR_CODE",
|
||||||
|
"validation_errors": [
|
||||||
|
{
|
||||||
|
"path": "trigger[0].platform",
|
||||||
|
"message": "Invalid trigger platform"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. Always validate configurations before saving
|
||||||
|
2. Use descriptive aliases and descriptions
|
||||||
|
3. Group related automations
|
||||||
|
4. Test automations in a safe environment
|
||||||
|
5. Document automation dependencies
|
||||||
|
6. Use variables for reusable values
|
||||||
|
7. Implement proper error handling
|
||||||
|
8. Consider automation modes carefully
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [Automation Management](automation.md)
|
||||||
|
- [Event Subscription](../events/subscribe-events.md)
|
||||||
|
- [Scene Management](../history-state/scene.md)
|
||||||
211
docs/tools/automation/automation.md
Normal file
211
docs/tools/automation/automation.md
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
# Automation Management Tool
|
||||||
|
|
||||||
|
The Automation Management tool provides functionality to manage and control Home Assistant automations.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- List all automations
|
||||||
|
- Get automation details
|
||||||
|
- Toggle automation state (enable/disable)
|
||||||
|
- Trigger automations manually
|
||||||
|
- Monitor automation execution
|
||||||
|
- View automation history
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### REST API
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
GET /api/automations
|
||||||
|
GET /api/automations/{automation_id}
|
||||||
|
POST /api/automations/{automation_id}/toggle
|
||||||
|
POST /api/automations/{automation_id}/trigger
|
||||||
|
GET /api/automations/{automation_id}/history
|
||||||
|
```
|
||||||
|
|
||||||
|
### WebSocket
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// List automations
|
||||||
|
{
|
||||||
|
"type": "get_automations"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle automation
|
||||||
|
{
|
||||||
|
"type": "toggle_automation",
|
||||||
|
"automation_id": "required_automation_id"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger automation
|
||||||
|
{
|
||||||
|
"type": "trigger_automation",
|
||||||
|
"automation_id": "required_automation_id",
|
||||||
|
"variables": {
|
||||||
|
// Optional variables
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### List All Automations
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/automations', {
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const automations = await response.json();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Toggle Automation State
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/automations/morning_routine/toggle', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Trigger Automation Manually
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/automations/morning_routine/trigger', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
"variables": {
|
||||||
|
"brightness": 100,
|
||||||
|
"temperature": 22
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Response Format
|
||||||
|
|
||||||
|
### Automation List Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"automations": [
|
||||||
|
{
|
||||||
|
"id": "automation_id",
|
||||||
|
"name": "Automation Name",
|
||||||
|
"enabled": true,
|
||||||
|
"last_triggered": "2024-02-05T12:00:00Z",
|
||||||
|
"trigger_count": 42
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Automation Details Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"automation": {
|
||||||
|
"id": "automation_id",
|
||||||
|
"name": "Automation Name",
|
||||||
|
"enabled": true,
|
||||||
|
"triggers": [
|
||||||
|
{
|
||||||
|
"platform": "time",
|
||||||
|
"at": "07:00:00"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"conditions": [],
|
||||||
|
"actions": [
|
||||||
|
{
|
||||||
|
"service": "light.turn_on",
|
||||||
|
"target": {
|
||||||
|
"entity_id": "light.bedroom"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mode": "single",
|
||||||
|
"max": 10,
|
||||||
|
"last_triggered": "2024-02-05T12:00:00Z",
|
||||||
|
"trigger_count": 42
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Automation History Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"history": [
|
||||||
|
{
|
||||||
|
"timestamp": "2024-02-05T12:00:00Z",
|
||||||
|
"trigger": {
|
||||||
|
"platform": "time",
|
||||||
|
"at": "07:00:00"
|
||||||
|
},
|
||||||
|
"context": {
|
||||||
|
"user_id": "user_123",
|
||||||
|
"variables": {}
|
||||||
|
},
|
||||||
|
"result": "success"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
### Common Error Codes
|
||||||
|
|
||||||
|
- `404`: Automation not found
|
||||||
|
- `401`: Unauthorized
|
||||||
|
- `400`: Invalid request
|
||||||
|
- `409`: Automation execution failed
|
||||||
|
|
||||||
|
### Error Response Format
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": false,
|
||||||
|
"message": "Error description",
|
||||||
|
"error_code": "ERROR_CODE"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rate Limiting
|
||||||
|
|
||||||
|
- Default limit: 50 requests per 15 minutes
|
||||||
|
- Configurable through environment variables:
|
||||||
|
- `AUTOMATION_RATE_LIMIT`
|
||||||
|
- `AUTOMATION_RATE_WINDOW`
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. Monitor automation execution history
|
||||||
|
2. Use descriptive automation names
|
||||||
|
3. Implement proper error handling
|
||||||
|
4. Cache automation configurations when possible
|
||||||
|
5. Handle rate limiting gracefully
|
||||||
|
6. Test automations before enabling
|
||||||
|
7. Use variables for flexible automation behavior
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [Automation Configuration](automation-config.md)
|
||||||
|
- [Event Subscription](../events/subscribe-events.md)
|
||||||
|
- [Device Control](../device-management/control.md)
|
||||||
195
docs/tools/device-management/control.md
Normal file
195
docs/tools/device-management/control.md
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
# Device Control Tool
|
||||||
|
|
||||||
|
The Device Control tool provides functionality to control various types of devices in your Home Assistant instance.
|
||||||
|
|
||||||
|
## Supported Device Types
|
||||||
|
|
||||||
|
- Lights
|
||||||
|
- Switches
|
||||||
|
- Covers
|
||||||
|
- Climate devices
|
||||||
|
- Media players
|
||||||
|
- And more...
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### REST API
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/devices/{device_id}/control
|
||||||
|
```
|
||||||
|
|
||||||
|
### WebSocket
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
"type": "control_device",
|
||||||
|
"device_id": "required_device_id",
|
||||||
|
"domain": "required_domain",
|
||||||
|
"service": "required_service",
|
||||||
|
"data": {
|
||||||
|
// Service-specific data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Domain-Specific Commands
|
||||||
|
|
||||||
|
### Lights
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Turn on/off
|
||||||
|
POST /api/devices/light/{device_id}/control
|
||||||
|
{
|
||||||
|
"service": "turn_on", // or "turn_off"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set brightness
|
||||||
|
{
|
||||||
|
"service": "turn_on",
|
||||||
|
"data": {
|
||||||
|
"brightness": 255 // 0-255
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set color
|
||||||
|
{
|
||||||
|
"service": "turn_on",
|
||||||
|
"data": {
|
||||||
|
"rgb_color": [255, 0, 0] // Red
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Covers
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Open/close
|
||||||
|
POST /api/devices/cover/{device_id}/control
|
||||||
|
{
|
||||||
|
"service": "open_cover", // or "close_cover"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set position
|
||||||
|
{
|
||||||
|
"service": "set_cover_position",
|
||||||
|
"data": {
|
||||||
|
"position": 50 // 0-100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Climate
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Set temperature
|
||||||
|
POST /api/devices/climate/{device_id}/control
|
||||||
|
{
|
||||||
|
"service": "set_temperature",
|
||||||
|
"data": {
|
||||||
|
"temperature": 22.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set mode
|
||||||
|
{
|
||||||
|
"service": "set_hvac_mode",
|
||||||
|
"data": {
|
||||||
|
"hvac_mode": "heat" // heat, cool, auto, off
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Control Light Brightness
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/devices/light/living_room/control', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
"service": "turn_on",
|
||||||
|
"data": {
|
||||||
|
"brightness": 128
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Control Cover Position
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/devices/cover/bedroom/control', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
"service": "set_cover_position",
|
||||||
|
"data": {
|
||||||
|
"position": 75
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Response Format
|
||||||
|
|
||||||
|
### Success Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"state": "on",
|
||||||
|
"attributes": {
|
||||||
|
// Updated device attributes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Error Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": false,
|
||||||
|
"message": "Error description",
|
||||||
|
"error_code": "ERROR_CODE"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
### Common Error Codes
|
||||||
|
|
||||||
|
- `404`: Device not found
|
||||||
|
- `401`: Unauthorized
|
||||||
|
- `400`: Invalid service or parameters
|
||||||
|
- `409`: Device unavailable or offline
|
||||||
|
|
||||||
|
## Rate Limiting
|
||||||
|
|
||||||
|
- Default limit: 100 requests per 15 minutes
|
||||||
|
- Configurable through environment variables:
|
||||||
|
- `DEVICE_CONTROL_RATE_LIMIT`
|
||||||
|
- `DEVICE_CONTROL_RATE_WINDOW`
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. Validate device availability before sending commands
|
||||||
|
2. Implement proper error handling
|
||||||
|
3. Use appropriate retry strategies for failed commands
|
||||||
|
4. Cache device capabilities when possible
|
||||||
|
5. Handle rate limiting gracefully
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [List Devices](list-devices.md)
|
||||||
|
- [Device History](../history-state/history.md)
|
||||||
|
- [Event Subscription](../events/subscribe-events.md)
|
||||||
139
docs/tools/device-management/list-devices.md
Normal file
139
docs/tools/device-management/list-devices.md
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
# List Devices Tool
|
||||||
|
|
||||||
|
The List Devices tool provides functionality to retrieve and manage device information from your Home Assistant instance.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- List all available Home Assistant devices
|
||||||
|
- Group devices by domain
|
||||||
|
- Get device states and attributes
|
||||||
|
- Filter devices by various criteria
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### REST API
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
GET /api/devices
|
||||||
|
GET /api/devices/{domain}
|
||||||
|
GET /api/devices/{device_id}/state
|
||||||
|
```
|
||||||
|
|
||||||
|
### WebSocket
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// List all devices
|
||||||
|
{
|
||||||
|
"type": "list_devices",
|
||||||
|
"domain": "optional_domain"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get device state
|
||||||
|
{
|
||||||
|
"type": "get_device_state",
|
||||||
|
"device_id": "required_device_id"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
#### List All Devices
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/devices', {
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const devices = await response.json();
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Get Devices by Domain
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/devices/light', {
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const lightDevices = await response.json();
|
||||||
|
```
|
||||||
|
|
||||||
|
## Response Format
|
||||||
|
|
||||||
|
### Device List Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"devices": [
|
||||||
|
{
|
||||||
|
"id": "device_id",
|
||||||
|
"name": "Device Name",
|
||||||
|
"domain": "light",
|
||||||
|
"state": "on",
|
||||||
|
"attributes": {
|
||||||
|
"brightness": 255,
|
||||||
|
"color_temp": 370
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Device State Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"state": "on",
|
||||||
|
"attributes": {
|
||||||
|
"brightness": 255,
|
||||||
|
"color_temp": 370
|
||||||
|
},
|
||||||
|
"last_changed": "2024-02-05T12:00:00Z",
|
||||||
|
"last_updated": "2024-02-05T12:00:00Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
### Common Error Codes
|
||||||
|
|
||||||
|
- `404`: Device not found
|
||||||
|
- `401`: Unauthorized
|
||||||
|
- `400`: Invalid request parameters
|
||||||
|
|
||||||
|
### Error Response Format
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": false,
|
||||||
|
"message": "Error description",
|
||||||
|
"error_code": "ERROR_CODE"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rate Limiting
|
||||||
|
|
||||||
|
- Default limit: 100 requests per 15 minutes
|
||||||
|
- Configurable through environment variables:
|
||||||
|
- `DEVICE_LIST_RATE_LIMIT`
|
||||||
|
- `DEVICE_LIST_RATE_WINDOW`
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. Cache device lists when possible
|
||||||
|
2. Use domain filtering for better performance
|
||||||
|
3. Implement proper error handling
|
||||||
|
4. Handle rate limiting gracefully
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [Device Control](control.md)
|
||||||
|
- [Device History](../history-state/history.md)
|
||||||
|
- [Event Subscription](../events/subscribe-events.md)
|
||||||
251
docs/tools/events/sse-stats.md
Normal file
251
docs/tools/events/sse-stats.md
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
# SSE Statistics Tool
|
||||||
|
|
||||||
|
The SSE Statistics tool provides functionality to monitor and analyze Server-Sent Events (SSE) connections and performance in your Home Assistant MCP instance.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Monitor active SSE connections
|
||||||
|
- Track connection statistics
|
||||||
|
- Analyze event delivery
|
||||||
|
- Monitor resource usage
|
||||||
|
- Connection management
|
||||||
|
- Performance metrics
|
||||||
|
- Historical data
|
||||||
|
- Alert configuration
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### REST API
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
GET /api/sse/stats
|
||||||
|
GET /api/sse/connections
|
||||||
|
GET /api/sse/connections/{connection_id}
|
||||||
|
GET /api/sse/metrics
|
||||||
|
GET /api/sse/history
|
||||||
|
```
|
||||||
|
|
||||||
|
### WebSocket
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Get SSE stats
|
||||||
|
{
|
||||||
|
"type": "get_sse_stats"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get connection details
|
||||||
|
{
|
||||||
|
"type": "get_sse_connection",
|
||||||
|
"connection_id": "required_connection_id"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get performance metrics
|
||||||
|
{
|
||||||
|
"type": "get_sse_metrics",
|
||||||
|
"period": "1h|24h|7d|30d"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Get Current Statistics
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/sse/stats', {
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const stats = await response.json();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Connection Details
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/sse/connections/conn_123', {
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const connection = await response.json();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Performance Metrics
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/sse/metrics?period=24h', {
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const metrics = await response.json();
|
||||||
|
```
|
||||||
|
|
||||||
|
## Response Format
|
||||||
|
|
||||||
|
### Statistics Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"active_connections": 42,
|
||||||
|
"total_events_sent": 12345,
|
||||||
|
"events_per_second": 5.2,
|
||||||
|
"memory_usage": 128974848,
|
||||||
|
"cpu_usage": 2.5,
|
||||||
|
"uptime": "PT24H",
|
||||||
|
"event_backlog": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Connection Details Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"connection": {
|
||||||
|
"id": "conn_123",
|
||||||
|
"client_id": "client_456",
|
||||||
|
"user_id": "user_789",
|
||||||
|
"connected_at": "2024-02-05T12:00:00Z",
|
||||||
|
"last_event_at": "2024-02-05T12:05:00Z",
|
||||||
|
"events_sent": 150,
|
||||||
|
"subscriptions": [
|
||||||
|
{
|
||||||
|
"event_type": "state_changed",
|
||||||
|
"entity_id": "light.living_room"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"state": "active",
|
||||||
|
"ip_address": "192.168.1.100",
|
||||||
|
"user_agent": "Mozilla/5.0 ..."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Performance Metrics Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"metrics": {
|
||||||
|
"connections": {
|
||||||
|
"current": 42,
|
||||||
|
"max": 100,
|
||||||
|
"average": 35.5
|
||||||
|
},
|
||||||
|
"events": {
|
||||||
|
"total": 12345,
|
||||||
|
"rate": {
|
||||||
|
"current": 5.2,
|
||||||
|
"max": 15.0,
|
||||||
|
"average": 4.8
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"latency": {
|
||||||
|
"p50": 15,
|
||||||
|
"p95": 45,
|
||||||
|
"p99": 100
|
||||||
|
},
|
||||||
|
"resources": {
|
||||||
|
"memory": {
|
||||||
|
"current": 128974848,
|
||||||
|
"max": 536870912
|
||||||
|
},
|
||||||
|
"cpu": {
|
||||||
|
"current": 2.5,
|
||||||
|
"max": 10.0,
|
||||||
|
"average": 3.2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"period": "24h",
|
||||||
|
"timestamp": "2024-02-05T12:00:00Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
### Common Error Codes
|
||||||
|
|
||||||
|
- `404`: Connection not found
|
||||||
|
- `401`: Unauthorized
|
||||||
|
- `400`: Invalid request parameters
|
||||||
|
- `503`: Service overloaded
|
||||||
|
|
||||||
|
### Error Response Format
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": false,
|
||||||
|
"message": "Error description",
|
||||||
|
"error_code": "ERROR_CODE"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Monitoring Metrics
|
||||||
|
|
||||||
|
### Connection Metrics
|
||||||
|
- Active connections
|
||||||
|
- Connection duration
|
||||||
|
- Connection state
|
||||||
|
- Client information
|
||||||
|
- Geographic distribution
|
||||||
|
- Protocol version
|
||||||
|
|
||||||
|
### Event Metrics
|
||||||
|
- Events per second
|
||||||
|
- Event types distribution
|
||||||
|
- Delivery success rate
|
||||||
|
- Event latency
|
||||||
|
- Queue size
|
||||||
|
- Backlog size
|
||||||
|
|
||||||
|
### Resource Metrics
|
||||||
|
- Memory usage
|
||||||
|
- CPU usage
|
||||||
|
- Network bandwidth
|
||||||
|
- Disk I/O
|
||||||
|
- Connection pool status
|
||||||
|
- Thread pool status
|
||||||
|
|
||||||
|
## Alert Thresholds
|
||||||
|
|
||||||
|
- Connection limits
|
||||||
|
- Event rate limits
|
||||||
|
- Resource usage limits
|
||||||
|
- Latency thresholds
|
||||||
|
- Error rate thresholds
|
||||||
|
- Backlog thresholds
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. Monitor connection health
|
||||||
|
2. Track resource usage
|
||||||
|
3. Set up alerts
|
||||||
|
4. Analyze usage patterns
|
||||||
|
5. Optimize performance
|
||||||
|
6. Plan capacity
|
||||||
|
7. Implement failover
|
||||||
|
8. Regular maintenance
|
||||||
|
|
||||||
|
## Performance Optimization
|
||||||
|
|
||||||
|
- Connection pooling
|
||||||
|
- Event batching
|
||||||
|
- Resource throttling
|
||||||
|
- Load balancing
|
||||||
|
- Cache optimization
|
||||||
|
- Connection cleanup
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [Event Subscription](subscribe-events.md)
|
||||||
|
- [Device Control](../device-management/control.md)
|
||||||
|
- [Automation Management](../automation/automation.md)
|
||||||
253
docs/tools/events/subscribe-events.md
Normal file
253
docs/tools/events/subscribe-events.md
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
# Event Subscription Tool
|
||||||
|
|
||||||
|
The Event Subscription tool provides functionality to subscribe to and monitor real-time events from your Home Assistant instance.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Subscribe to Home Assistant events
|
||||||
|
- Monitor specific entities
|
||||||
|
- Domain-based monitoring
|
||||||
|
- Event filtering
|
||||||
|
- Real-time updates
|
||||||
|
- Event history
|
||||||
|
- Custom event handling
|
||||||
|
- Connection management
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### REST API
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/events/subscribe
|
||||||
|
DELETE /api/events/unsubscribe
|
||||||
|
GET /api/events/subscriptions
|
||||||
|
GET /api/events/history
|
||||||
|
```
|
||||||
|
|
||||||
|
### WebSocket
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Subscribe to events
|
||||||
|
{
|
||||||
|
"type": "subscribe_events",
|
||||||
|
"event_type": "optional_event_type",
|
||||||
|
"entity_id": "optional_entity_id",
|
||||||
|
"domain": "optional_domain"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unsubscribe from events
|
||||||
|
{
|
||||||
|
"type": "unsubscribe_events",
|
||||||
|
"subscription_id": "required_subscription_id"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Server-Sent Events (SSE)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
GET /api/events/stream?event_type=state_changed&entity_id=light.living_room
|
||||||
|
```
|
||||||
|
|
||||||
|
## Event Types
|
||||||
|
|
||||||
|
- `state_changed`: Entity state changes
|
||||||
|
- `automation_triggered`: Automation executions
|
||||||
|
- `scene_activated`: Scene activations
|
||||||
|
- `device_registered`: New device registrations
|
||||||
|
- `service_registered`: New service registrations
|
||||||
|
- `homeassistant_start`: System startup
|
||||||
|
- `homeassistant_stop`: System shutdown
|
||||||
|
- Custom events
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Subscribe to All State Changes
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/events/subscribe', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
"event_type": "state_changed"
|
||||||
|
})
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Monitor Specific Entity
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/events/subscribe', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
"event_type": "state_changed",
|
||||||
|
"entity_id": "light.living_room"
|
||||||
|
})
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Domain-Based Monitoring
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/events/subscribe', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
"event_type": "state_changed",
|
||||||
|
"domain": "light"
|
||||||
|
})
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### SSE Connection Example
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const eventSource = new EventSource(
|
||||||
|
'http://your-ha-mcp/api/events/stream?event_type=state_changed&entity_id=light.living_room',
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
eventSource.onmessage = (event) => {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
console.log('Event received:', data);
|
||||||
|
};
|
||||||
|
|
||||||
|
eventSource.onerror = (error) => {
|
||||||
|
console.error('SSE error:', error);
|
||||||
|
eventSource.close();
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Response Format
|
||||||
|
|
||||||
|
### Subscription Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"subscription_id": "sub_123",
|
||||||
|
"event_type": "state_changed",
|
||||||
|
"entity_id": "light.living_room",
|
||||||
|
"created_at": "2024-02-05T12:00:00Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Event Message Format
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"event_type": "state_changed",
|
||||||
|
"entity_id": "light.living_room",
|
||||||
|
"data": {
|
||||||
|
"old_state": {
|
||||||
|
"state": "off",
|
||||||
|
"attributes": {},
|
||||||
|
"last_changed": "2024-02-05T11:55:00Z"
|
||||||
|
},
|
||||||
|
"new_state": {
|
||||||
|
"state": "on",
|
||||||
|
"attributes": {
|
||||||
|
"brightness": 255
|
||||||
|
},
|
||||||
|
"last_changed": "2024-02-05T12:00:00Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"origin": "LOCAL",
|
||||||
|
"time_fired": "2024-02-05T12:00:00Z",
|
||||||
|
"context": {
|
||||||
|
"id": "context_123",
|
||||||
|
"parent_id": null,
|
||||||
|
"user_id": "user_123"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Subscriptions List Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"subscriptions": [
|
||||||
|
{
|
||||||
|
"id": "sub_123",
|
||||||
|
"event_type": "state_changed",
|
||||||
|
"entity_id": "light.living_room",
|
||||||
|
"created_at": "2024-02-05T12:00:00Z",
|
||||||
|
"last_event": "2024-02-05T12:05:00Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
### Common Error Codes
|
||||||
|
|
||||||
|
- `404`: Event type not found
|
||||||
|
- `401`: Unauthorized
|
||||||
|
- `400`: Invalid subscription parameters
|
||||||
|
- `409`: Subscription already exists
|
||||||
|
- `429`: Too many subscriptions
|
||||||
|
|
||||||
|
### Error Response Format
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": false,
|
||||||
|
"message": "Error description",
|
||||||
|
"error_code": "ERROR_CODE"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rate Limiting
|
||||||
|
|
||||||
|
- Default limits:
|
||||||
|
- Maximum subscriptions: 100 per client
|
||||||
|
- Maximum event rate: 1000 events per minute
|
||||||
|
- Configurable through environment variables:
|
||||||
|
- `EVENT_SUB_MAX_SUBSCRIPTIONS`
|
||||||
|
- `EVENT_SUB_RATE_LIMIT`
|
||||||
|
- `EVENT_SUB_RATE_WINDOW`
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. Use specific event types when possible
|
||||||
|
2. Implement proper error handling
|
||||||
|
3. Handle connection interruptions
|
||||||
|
4. Process events asynchronously
|
||||||
|
5. Implement backoff strategies
|
||||||
|
6. Monitor subscription health
|
||||||
|
7. Clean up unused subscriptions
|
||||||
|
8. Handle rate limiting gracefully
|
||||||
|
|
||||||
|
## Connection Management
|
||||||
|
|
||||||
|
- Implement heartbeat monitoring
|
||||||
|
- Use reconnection strategies
|
||||||
|
- Handle connection timeouts
|
||||||
|
- Monitor connection quality
|
||||||
|
- Implement fallback mechanisms
|
||||||
|
- Clean up resources properly
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [SSE Statistics](sse-stats.md)
|
||||||
|
- [Device Control](../device-management/control.md)
|
||||||
|
- [Automation Management](../automation/automation.md)
|
||||||
167
docs/tools/history-state/history.md
Normal file
167
docs/tools/history-state/history.md
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
# Device History Tool
|
||||||
|
|
||||||
|
The Device History tool allows you to retrieve historical state information for devices in your Home Assistant instance.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Fetch device state history
|
||||||
|
- Filter by time range
|
||||||
|
- Get significant changes
|
||||||
|
- Aggregate data by time periods
|
||||||
|
- Export historical data
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### REST API
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
GET /api/history/{device_id}
|
||||||
|
GET /api/history/{device_id}/period/{start_time}
|
||||||
|
GET /api/history/{device_id}/period/{start_time}/{end_time}
|
||||||
|
```
|
||||||
|
|
||||||
|
### WebSocket
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
"type": "get_history",
|
||||||
|
"device_id": "required_device_id",
|
||||||
|
"start_time": "optional_iso_timestamp",
|
||||||
|
"end_time": "optional_iso_timestamp",
|
||||||
|
"significant_changes_only": false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Query Parameters
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
|-----------|------|-------------|
|
||||||
|
| `start_time` | ISO timestamp | Start of the period to fetch history for |
|
||||||
|
| `end_time` | ISO timestamp | End of the period to fetch history for |
|
||||||
|
| `significant_changes_only` | boolean | Only return significant state changes |
|
||||||
|
| `minimal_response` | boolean | Return minimal state information |
|
||||||
|
| `no_attributes` | boolean | Exclude attribute data from response |
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Get Recent History
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/history/light.living_room', {
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const history = await response.json();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get History for Specific Period
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const startTime = '2024-02-01T00:00:00Z';
|
||||||
|
const endTime = '2024-02-02T00:00:00Z';
|
||||||
|
const response = await fetch(
|
||||||
|
`http://your-ha-mcp/api/history/light.living_room/period/${startTime}/${endTime}`,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const history = await response.json();
|
||||||
|
```
|
||||||
|
|
||||||
|
## Response Format
|
||||||
|
|
||||||
|
### History Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"history": [
|
||||||
|
{
|
||||||
|
"state": "on",
|
||||||
|
"attributes": {
|
||||||
|
"brightness": 255
|
||||||
|
},
|
||||||
|
"last_changed": "2024-02-05T12:00:00Z",
|
||||||
|
"last_updated": "2024-02-05T12:00:00Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"state": "off",
|
||||||
|
"last_changed": "2024-02-05T13:00:00Z",
|
||||||
|
"last_updated": "2024-02-05T13:00:00Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Aggregated History Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"aggregates": {
|
||||||
|
"daily": [
|
||||||
|
{
|
||||||
|
"date": "2024-02-05",
|
||||||
|
"on_time": "PT5H30M",
|
||||||
|
"off_time": "PT18H30M",
|
||||||
|
"changes": 10
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
### Common Error Codes
|
||||||
|
|
||||||
|
- `404`: Device not found
|
||||||
|
- `401`: Unauthorized
|
||||||
|
- `400`: Invalid parameters
|
||||||
|
- `416`: Time range too large
|
||||||
|
|
||||||
|
### Error Response Format
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": false,
|
||||||
|
"message": "Error description",
|
||||||
|
"error_code": "ERROR_CODE"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rate Limiting
|
||||||
|
|
||||||
|
- Default limit: 50 requests per 15 minutes
|
||||||
|
- Configurable through environment variables:
|
||||||
|
- `HISTORY_RATE_LIMIT`
|
||||||
|
- `HISTORY_RATE_WINDOW`
|
||||||
|
|
||||||
|
## Data Retention
|
||||||
|
|
||||||
|
- Default retention period: 30 days
|
||||||
|
- Configurable through environment variables:
|
||||||
|
- `HISTORY_RETENTION_DAYS`
|
||||||
|
- Older data may be automatically aggregated
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. Use appropriate time ranges to avoid large responses
|
||||||
|
2. Enable `significant_changes_only` for better performance
|
||||||
|
3. Use `minimal_response` when full state data isn't needed
|
||||||
|
4. Implement proper error handling
|
||||||
|
5. Cache frequently accessed historical data
|
||||||
|
6. Handle rate limiting gracefully
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [List Devices](../device-management/list-devices.md)
|
||||||
|
- [Device Control](../device-management/control.md)
|
||||||
|
- [Scene Management](scene.md)
|
||||||
215
docs/tools/history-state/scene.md
Normal file
215
docs/tools/history-state/scene.md
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
# Scene Management Tool
|
||||||
|
|
||||||
|
The Scene Management tool provides functionality to manage and control scenes in your Home Assistant instance.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- List available scenes
|
||||||
|
- Activate scenes
|
||||||
|
- Create new scenes
|
||||||
|
- Update existing scenes
|
||||||
|
- Delete scenes
|
||||||
|
- Get scene state information
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### REST API
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
GET /api/scenes
|
||||||
|
GET /api/scenes/{scene_id}
|
||||||
|
POST /api/scenes/{scene_id}/activate
|
||||||
|
POST /api/scenes
|
||||||
|
PUT /api/scenes/{scene_id}
|
||||||
|
DELETE /api/scenes/{scene_id}
|
||||||
|
```
|
||||||
|
|
||||||
|
### WebSocket
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// List scenes
|
||||||
|
{
|
||||||
|
"type": "get_scenes"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Activate scene
|
||||||
|
{
|
||||||
|
"type": "activate_scene",
|
||||||
|
"scene_id": "required_scene_id"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create/Update scene
|
||||||
|
{
|
||||||
|
"type": "create_scene",
|
||||||
|
"scene": {
|
||||||
|
"name": "required_scene_name",
|
||||||
|
"entities": {
|
||||||
|
// Entity states
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Scene Configuration
|
||||||
|
|
||||||
|
### Scene Definition
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "Movie Night",
|
||||||
|
"entities": {
|
||||||
|
"light.living_room": {
|
||||||
|
"state": "on",
|
||||||
|
"brightness": 50,
|
||||||
|
"color_temp": 2700
|
||||||
|
},
|
||||||
|
"cover.living_room": {
|
||||||
|
"state": "closed"
|
||||||
|
},
|
||||||
|
"media_player.tv": {
|
||||||
|
"state": "on",
|
||||||
|
"source": "HDMI 1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### List All Scenes
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/scenes', {
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const scenes = await response.json();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Activate a Scene
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/scenes/movie_night/activate', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Create a New Scene
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/scenes', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
"name": "Movie Night",
|
||||||
|
"entities": {
|
||||||
|
"light.living_room": {
|
||||||
|
"state": "on",
|
||||||
|
"brightness": 50
|
||||||
|
},
|
||||||
|
"cover.living_room": {
|
||||||
|
"state": "closed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Response Format
|
||||||
|
|
||||||
|
### Scene List Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"scenes": [
|
||||||
|
{
|
||||||
|
"id": "scene_id",
|
||||||
|
"name": "Scene Name",
|
||||||
|
"entities": {
|
||||||
|
// Entity configurations
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Scene Activation Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"scene_id": "activated_scene_id",
|
||||||
|
"status": "activated",
|
||||||
|
"timestamp": "2024-02-05T12:00:00Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
### Common Error Codes
|
||||||
|
|
||||||
|
- `404`: Scene not found
|
||||||
|
- `401`: Unauthorized
|
||||||
|
- `400`: Invalid scene configuration
|
||||||
|
- `409`: Scene activation failed
|
||||||
|
|
||||||
|
### Error Response Format
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": false,
|
||||||
|
"message": "Error description",
|
||||||
|
"error_code": "ERROR_CODE"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rate Limiting
|
||||||
|
|
||||||
|
- Default limit: 50 requests per 15 minutes
|
||||||
|
- Configurable through environment variables:
|
||||||
|
- `SCENE_RATE_LIMIT`
|
||||||
|
- `SCENE_RATE_WINDOW`
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. Validate entity availability before creating scenes
|
||||||
|
2. Use meaningful scene names
|
||||||
|
3. Group related entities in scenes
|
||||||
|
4. Implement proper error handling
|
||||||
|
5. Cache scene configurations when possible
|
||||||
|
6. Handle rate limiting gracefully
|
||||||
|
|
||||||
|
## Scene Transitions
|
||||||
|
|
||||||
|
Scenes can include transition settings for smooth state changes:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "Sunset Mode",
|
||||||
|
"entities": {
|
||||||
|
"light.living_room": {
|
||||||
|
"state": "on",
|
||||||
|
"brightness": 128,
|
||||||
|
"transition": 5 // 5 seconds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [Device Control](../device-management/control.md)
|
||||||
|
- [Device History](history.md)
|
||||||
|
- [Automation Management](../automation/automation.md)
|
||||||
249
docs/tools/notifications/notify.md
Normal file
249
docs/tools/notifications/notify.md
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
# Notification Tool
|
||||||
|
|
||||||
|
The Notification tool provides functionality to send notifications through various services in your Home Assistant instance.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Send notifications
|
||||||
|
- Support for multiple notification services
|
||||||
|
- Custom notification data
|
||||||
|
- Rich media support
|
||||||
|
- Notification templates
|
||||||
|
- Delivery tracking
|
||||||
|
- Priority levels
|
||||||
|
- Notification groups
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### REST API
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/notify
|
||||||
|
POST /api/notify/{service_id}
|
||||||
|
GET /api/notify/services
|
||||||
|
GET /api/notify/history
|
||||||
|
```
|
||||||
|
|
||||||
|
### WebSocket
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Send notification
|
||||||
|
{
|
||||||
|
"type": "send_notification",
|
||||||
|
"service": "required_service_id",
|
||||||
|
"message": "required_message",
|
||||||
|
"title": "optional_title",
|
||||||
|
"data": {
|
||||||
|
// Service-specific data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get notification services
|
||||||
|
{
|
||||||
|
"type": "get_notification_services"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Supported Services
|
||||||
|
|
||||||
|
- Mobile App
|
||||||
|
- Email
|
||||||
|
- SMS
|
||||||
|
- Telegram
|
||||||
|
- Discord
|
||||||
|
- Slack
|
||||||
|
- Push Notifications
|
||||||
|
- Custom Services
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Basic Notification
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/notify/mobile_app', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
"message": "Motion detected in living room",
|
||||||
|
"title": "Security Alert"
|
||||||
|
})
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Rich Notification
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/notify/mobile_app', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
"message": "Motion detected in living room",
|
||||||
|
"title": "Security Alert",
|
||||||
|
"data": {
|
||||||
|
"image": "https://your-camera-snapshot.jpg",
|
||||||
|
"actions": [
|
||||||
|
{
|
||||||
|
"action": "view_camera",
|
||||||
|
"title": "View Camera"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "dismiss",
|
||||||
|
"title": "Dismiss"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"priority": "high",
|
||||||
|
"ttl": 3600,
|
||||||
|
"group": "security"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Service-Specific Example (Telegram)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await fetch('http://your-ha-mcp/api/notify/telegram', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer your_access_token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
"message": "Temperature is too high!",
|
||||||
|
"title": "Climate Alert",
|
||||||
|
"data": {
|
||||||
|
"parse_mode": "markdown",
|
||||||
|
"inline_keyboard": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"text": "Turn On AC",
|
||||||
|
"callback_data": "turn_on_ac"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Response Format
|
||||||
|
|
||||||
|
### Success Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"notification_id": "notification_123",
|
||||||
|
"status": "sent",
|
||||||
|
"timestamp": "2024-02-05T12:00:00Z",
|
||||||
|
"service": "mobile_app"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Services List Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"id": "mobile_app",
|
||||||
|
"name": "Mobile App",
|
||||||
|
"enabled": true,
|
||||||
|
"features": [
|
||||||
|
"actions",
|
||||||
|
"images",
|
||||||
|
"sound"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Notification History Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"history": [
|
||||||
|
{
|
||||||
|
"id": "notification_123",
|
||||||
|
"service": "mobile_app",
|
||||||
|
"message": "Motion detected",
|
||||||
|
"title": "Security Alert",
|
||||||
|
"timestamp": "2024-02-05T12:00:00Z",
|
||||||
|
"status": "delivered"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
### Common Error Codes
|
||||||
|
|
||||||
|
- `404`: Service not found
|
||||||
|
- `401`: Unauthorized
|
||||||
|
- `400`: Invalid request
|
||||||
|
- `408`: Delivery timeout
|
||||||
|
- `422`: Invalid notification data
|
||||||
|
|
||||||
|
### Error Response Format
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": false,
|
||||||
|
"message": "Error description",
|
||||||
|
"error_code": "ERROR_CODE"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rate Limiting
|
||||||
|
|
||||||
|
- Default limit: 100 notifications per hour
|
||||||
|
- Configurable through environment variables:
|
||||||
|
- `NOTIFY_RATE_LIMIT`
|
||||||
|
- `NOTIFY_RATE_WINDOW`
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. Use appropriate priority levels
|
||||||
|
2. Group related notifications
|
||||||
|
3. Include relevant context
|
||||||
|
4. Implement proper error handling
|
||||||
|
5. Use templates for consistency
|
||||||
|
6. Consider time zones
|
||||||
|
7. Respect user preferences
|
||||||
|
8. Handle rate limiting gracefully
|
||||||
|
|
||||||
|
## Notification Templates
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Template example
|
||||||
|
{
|
||||||
|
"template": "security_alert",
|
||||||
|
"data": {
|
||||||
|
"location": "living_room",
|
||||||
|
"event_type": "motion",
|
||||||
|
"timestamp": "2024-02-05T12:00:00Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [Event Subscription](../events/subscribe-events.md)
|
||||||
|
- [Device Control](../device-management/control.md)
|
||||||
|
- [Automation Management](../automation/automation.md)
|
||||||
@@ -6,36 +6,36 @@ This section documents all available tools in the Home Assistant MCP.
|
|||||||
|
|
||||||
### Device Management
|
### Device Management
|
||||||
|
|
||||||
1. [List Devices](./list-devices.md)
|
1. [List Devices](device-management/list-devices.md)
|
||||||
- List all available Home Assistant devices
|
- List all available Home Assistant devices
|
||||||
- Group devices by domain
|
- Group devices by domain
|
||||||
- Get device states and attributes
|
- Get device states and attributes
|
||||||
|
|
||||||
2. [Device Control](./control.md)
|
2. [Device Control](device-management/control.md)
|
||||||
- Control various device types
|
- Control various device types
|
||||||
- Support for lights, switches, covers, climate devices
|
- Support for lights, switches, covers, climate devices
|
||||||
- Domain-specific commands and parameters
|
- Domain-specific commands and parameters
|
||||||
|
|
||||||
### History and State
|
### History and State
|
||||||
|
|
||||||
1. [History](./history.md)
|
1. [History](history-state/history.md)
|
||||||
- Fetch device state history
|
- Fetch device state history
|
||||||
- Filter by time range
|
- Filter by time range
|
||||||
- Get significant changes
|
- Get significant changes
|
||||||
|
|
||||||
2. [Scene Management](./scene.md)
|
2. [Scene Management](history-state/scene.md)
|
||||||
- List available scenes
|
- List available scenes
|
||||||
- Activate scenes
|
- Activate scenes
|
||||||
- Scene state information
|
- Scene state information
|
||||||
|
|
||||||
### Automation
|
### Automation
|
||||||
|
|
||||||
1. [Automation Management](./automation.md)
|
1. [Automation Management](automation/automation.md)
|
||||||
- List automations
|
- List automations
|
||||||
- Toggle automation state
|
- Toggle automation state
|
||||||
- Trigger automations manually
|
- Trigger automations manually
|
||||||
|
|
||||||
2. [Automation Configuration](./automation-config.md)
|
2. [Automation Configuration](automation/automation-config.md)
|
||||||
- Create new automations
|
- Create new automations
|
||||||
- Update existing automations
|
- Update existing automations
|
||||||
- Delete automations
|
- Delete automations
|
||||||
@@ -43,32 +43,32 @@ This section documents all available tools in the Home Assistant MCP.
|
|||||||
|
|
||||||
### Add-ons and Packages
|
### Add-ons and Packages
|
||||||
|
|
||||||
1. [Add-on Management](./addon.md)
|
1. [Add-on Management](addons-packages/addon.md)
|
||||||
- List available add-ons
|
- List available add-ons
|
||||||
- Install/uninstall add-ons
|
- Install/uninstall add-ons
|
||||||
- Start/stop/restart add-ons
|
- Start/stop/restart add-ons
|
||||||
- Get add-on information
|
- Get add-on information
|
||||||
|
|
||||||
2. [Package Management](./package.md)
|
2. [Package Management](addons-packages/package.md)
|
||||||
- Manage HACS packages
|
- Manage HACS packages
|
||||||
- Install/update/remove packages
|
- Install/update/remove packages
|
||||||
- List available packages by category
|
- List available packages by category
|
||||||
|
|
||||||
### Notifications
|
### Notifications
|
||||||
|
|
||||||
1. [Notify](./notify.md)
|
1. [Notify](notifications/notify.md)
|
||||||
- Send notifications
|
- Send notifications
|
||||||
- Support for multiple notification services
|
- Support for multiple notification services
|
||||||
- Custom notification data
|
- Custom notification data
|
||||||
|
|
||||||
### Real-time Events
|
### Real-time Events
|
||||||
|
|
||||||
1. [Event Subscription](./subscribe-events.md)
|
1. [Event Subscription](events/subscribe-events.md)
|
||||||
- Subscribe to Home Assistant events
|
- Subscribe to Home Assistant events
|
||||||
- Monitor specific entities
|
- Monitor specific entities
|
||||||
- Domain-based monitoring
|
- Domain-based monitoring
|
||||||
|
|
||||||
2. [SSE Statistics](./sse-stats.md)
|
2. [SSE Statistics](events/sse-stats.md)
|
||||||
- Get SSE connection statistics
|
- Get SSE connection statistics
|
||||||
- Monitor active subscriptions
|
- Monitor active subscriptions
|
||||||
- Connection management
|
- Connection management
|
||||||
|
|||||||
@@ -1,345 +1,315 @@
|
|||||||
# Troubleshooting Guide
|
---
|
||||||
|
layout: default
|
||||||
|
title: Troubleshooting
|
||||||
|
nav_order: 6
|
||||||
|
---
|
||||||
|
|
||||||
This guide provides solutions to common issues encountered with the Home Assistant MCP Server.
|
# Troubleshooting Guide 🔧
|
||||||
|
|
||||||
|
This guide helps you diagnose and resolve common issues with MCP Server.
|
||||||
|
|
||||||
|
## Quick Diagnostics
|
||||||
|
|
||||||
|
### Health Check
|
||||||
|
|
||||||
|
First, verify the server's health:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://localhost:3000/health
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "healthy",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"uptime": 3600,
|
||||||
|
"homeAssistant": {
|
||||||
|
"connected": true,
|
||||||
|
"version": "2024.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Common Issues
|
## Common Issues
|
||||||
|
|
||||||
- **Server Not Starting:**
|
### 1. Connection Issues
|
||||||
- Verify that all required environment variables are correctly set.
|
|
||||||
- Check for port conflicts or missing dependencies.
|
|
||||||
- Review the server logs for error details.
|
|
||||||
|
|
||||||
- **Connection Problems:**
|
#### Cannot Connect to MCP Server
|
||||||
- Ensure your Home Assistant instance is reachable.
|
|
||||||
- Confirm that the authentication token is valid.
|
|
||||||
- Check network configurations and firewalls.
|
|
||||||
|
|
||||||
## Tool Issues
|
|
||||||
|
|
||||||
### Tool Not Found
|
|
||||||
|
|
||||||
**Symptoms:**
|
**Symptoms:**
|
||||||
- "Tool not found" errors or 404 responses.
|
- Server not responding
|
||||||
|
- Connection refused errors
|
||||||
|
- Timeout errors
|
||||||
|
|
||||||
**Solutions:**
|
**Solutions:**
|
||||||
- Double-check the tool name spelling.
|
|
||||||
- Verify that the tool is correctly registered.
|
|
||||||
- Review tool imports and documentation.
|
|
||||||
|
|
||||||
### Tool Execution Failures
|
1. Check if the server is running:
|
||||||
|
```bash
|
||||||
|
# For Docker installation
|
||||||
|
docker compose ps
|
||||||
|
|
||||||
|
# For manual installation
|
||||||
|
ps aux | grep mcp
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Verify port availability:
|
||||||
|
```bash
|
||||||
|
# Check if port is in use
|
||||||
|
netstat -tuln | grep 3000
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Check logs:
|
||||||
|
```bash
|
||||||
|
# Docker logs
|
||||||
|
docker compose logs mcp
|
||||||
|
|
||||||
|
# Manual installation logs
|
||||||
|
bun run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Home Assistant Connection Failed
|
||||||
|
|
||||||
**Symptoms:**
|
**Symptoms:**
|
||||||
- Execution errors or timeouts.
|
- "Connection Error" in health check
|
||||||
|
- Cannot control devices
|
||||||
|
- State updates not working
|
||||||
|
|
||||||
**Solutions:**
|
**Solutions:**
|
||||||
- Validate input parameters.
|
|
||||||
- Check and review error logs.
|
|
||||||
- Debug the tool implementation.
|
|
||||||
- Ensure proper permissions in Home Assistant.
|
|
||||||
|
|
||||||
## Debugging Steps
|
1. Verify Home Assistant URL and token in `.env`:
|
||||||
|
|
||||||
### Server Logs
|
|
||||||
|
|
||||||
1. Enable debug logging by setting:
|
|
||||||
```env
|
```env
|
||||||
LOG_LEVEL=debug
|
HA_URL=http://homeassistant:8123
|
||||||
|
HA_TOKEN=your_long_lived_access_token
|
||||||
```
|
```
|
||||||
2. Check logs:
|
|
||||||
|
2. Test Home Assistant connection:
|
||||||
```bash
|
```bash
|
||||||
npm run logs
|
curl -H "Authorization: Bearer YOUR_HA_TOKEN" \
|
||||||
|
http://your-homeassistant:8123/api/
|
||||||
```
|
```
|
||||||
3. Filter errors:
|
|
||||||
|
3. Check network connectivity:
|
||||||
```bash
|
```bash
|
||||||
npm run logs | grep "error"
|
# For Docker setup
|
||||||
|
docker compose exec mcp ping homeassistant
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 2. Authentication Issues
|
||||||
|
|
||||||
|
#### Invalid Token
|
||||||
|
|
||||||
|
**Symptoms:**
|
||||||
|
- 401 Unauthorized responses
|
||||||
|
- "Invalid token" errors
|
||||||
|
|
||||||
|
**Solutions:**
|
||||||
|
|
||||||
|
1. Generate a new token:
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:3000/auth/token \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"username": "your_username", "password": "your_password"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Verify token format:
|
||||||
|
```javascript
|
||||||
|
// Token should be in format:
|
||||||
|
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Rate Limiting
|
||||||
|
|
||||||
|
**Symptoms:**
|
||||||
|
- 429 Too Many Requests
|
||||||
|
- "Rate limit exceeded" errors
|
||||||
|
|
||||||
|
**Solutions:**
|
||||||
|
|
||||||
|
1. Check current rate limit status:
|
||||||
|
```bash
|
||||||
|
curl -I http://localhost:3000/api/state
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Adjust rate limits in configuration:
|
||||||
|
```yaml
|
||||||
|
security:
|
||||||
|
rateLimit: 100 # Increase if needed
|
||||||
|
rateLimitWindow: 60000 # Window in milliseconds
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Real-time Updates Issues
|
||||||
|
|
||||||
|
#### SSE Connection Drops
|
||||||
|
|
||||||
|
**Symptoms:**
|
||||||
|
- Frequent disconnections
|
||||||
|
- Missing state updates
|
||||||
|
- EventSource errors
|
||||||
|
|
||||||
|
**Solutions:**
|
||||||
|
|
||||||
|
1. Implement proper reconnection logic:
|
||||||
|
```javascript
|
||||||
|
class SSEClient {
|
||||||
|
constructor() {
|
||||||
|
this.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
this.eventSource = new EventSource('/subscribe_events');
|
||||||
|
this.eventSource.onerror = this.handleError.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleError(error) {
|
||||||
|
console.error('SSE Error:', error);
|
||||||
|
this.eventSource.close();
|
||||||
|
setTimeout(() => this.connect(), 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Check network stability:
|
||||||
|
```bash
|
||||||
|
# Monitor connection stability
|
||||||
|
ping -c 100 localhost
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Performance Issues
|
||||||
|
|
||||||
|
#### High Latency
|
||||||
|
|
||||||
|
**Symptoms:**
|
||||||
|
- Slow response times
|
||||||
|
- Command execution delays
|
||||||
|
- UI lag
|
||||||
|
|
||||||
|
**Solutions:**
|
||||||
|
|
||||||
|
1. Enable Redis caching:
|
||||||
|
```env
|
||||||
|
REDIS_ENABLED=true
|
||||||
|
REDIS_URL=redis://localhost:6379
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Monitor system resources:
|
||||||
|
```bash
|
||||||
|
# Check CPU and memory usage
|
||||||
|
docker stats
|
||||||
|
|
||||||
|
# Or for manual installation
|
||||||
|
top -p $(pgrep -f mcp)
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Optimize database queries and caching:
|
||||||
|
```typescript
|
||||||
|
// Use batch operations
|
||||||
|
const results = await Promise.all([
|
||||||
|
cache.get('key1'),
|
||||||
|
cache.get('key2')
|
||||||
|
]);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Device Control Issues
|
||||||
|
|
||||||
|
#### Commands Not Executing
|
||||||
|
|
||||||
|
**Symptoms:**
|
||||||
|
- Commands appear successful but no device response
|
||||||
|
- Inconsistent device states
|
||||||
|
- Error messages from Home Assistant
|
||||||
|
|
||||||
|
**Solutions:**
|
||||||
|
|
||||||
|
1. Verify device availability:
|
||||||
|
```bash
|
||||||
|
curl http://localhost:3000/api/state/light.living_room
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Check command syntax:
|
||||||
|
```bash
|
||||||
|
# Test basic command
|
||||||
|
curl -X POST http://localhost:3000/api/command \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"command": "Turn on living room lights"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Review Home Assistant logs:
|
||||||
|
```bash
|
||||||
|
docker compose exec homeassistant journalctl -f
|
||||||
|
```
|
||||||
|
|
||||||
|
## Debugging Tools
|
||||||
|
|
||||||
|
### Log Analysis
|
||||||
|
|
||||||
|
Enable debug logging:
|
||||||
|
|
||||||
|
```env
|
||||||
|
LOG_LEVEL=debug
|
||||||
|
DEBUG=mcp:*
|
||||||
|
```
|
||||||
|
|
||||||
### Network Debugging
|
### Network Debugging
|
||||||
|
|
||||||
1. Test API endpoints:
|
Monitor network traffic:
|
||||||
```bash
|
|
||||||
curl -v http://localhost:3000/api/health
|
|
||||||
```
|
|
||||||
2. Monitor SSE connections:
|
|
||||||
```bash
|
|
||||||
curl -N http://localhost:3000/api/sse/stats
|
|
||||||
```
|
|
||||||
3. Test WebSocket connectivity:
|
|
||||||
```bash
|
|
||||||
wscat -c ws://localhost:3000
|
|
||||||
```
|
|
||||||
|
|
||||||
### Performance Issues
|
```bash
|
||||||
|
# TCP dump for API traffic
|
||||||
|
tcpdump -i any port 3000 -w debug.pcap
|
||||||
|
```
|
||||||
|
|
||||||
- Monitor memory usage with:
|
### Performance Profiling
|
||||||
```bash
|
|
||||||
npm run stats
|
|
||||||
```
|
|
||||||
|
|
||||||
## Security Middleware Troubleshooting
|
Enable performance monitoring:
|
||||||
|
|
||||||
### Rate Limiting Problems
|
```env
|
||||||
|
ENABLE_METRICS=true
|
||||||
**Symptoms:** Receiving 429 (Too Many Requests) errors.
|
METRICS_PORT=9090
|
||||||
|
```
|
||||||
**Solutions:**
|
|
||||||
- Adjust and fine-tune rate limit settings.
|
|
||||||
- Consider different limits for critical versus non-critical endpoints.
|
|
||||||
|
|
||||||
### Request Validation Failures
|
|
||||||
|
|
||||||
**Symptoms:** 400 or 415 errors on valid requests.
|
|
||||||
|
|
||||||
**Solutions:**
|
|
||||||
- Verify that the `Content-Type` header is set correctly.
|
|
||||||
- Inspect request payload size and format.
|
|
||||||
|
|
||||||
### Input Sanitization Issues
|
|
||||||
|
|
||||||
**Symptoms:** Unexpected data transformation or loss.
|
|
||||||
|
|
||||||
**Solutions:**
|
|
||||||
- Test sanitization with various input types.
|
|
||||||
- Implement custom sanitization for complex data if needed.
|
|
||||||
|
|
||||||
### Security Header Configuration
|
|
||||||
|
|
||||||
**Symptoms:** Missing or improper security headers.
|
|
||||||
|
|
||||||
**Solutions:**
|
|
||||||
- Review and update security header configurations (e.g., Helmet settings).
|
|
||||||
- Ensure environment-specific header settings are in place.
|
|
||||||
|
|
||||||
### Error Handling and Logging
|
|
||||||
|
|
||||||
**Symptoms:** Inconsistent error responses.
|
|
||||||
|
|
||||||
**Solutions:**
|
|
||||||
- Enhance logging for detailed error tracking.
|
|
||||||
- Adjust error handlers for production and development differences.
|
|
||||||
|
|
||||||
## Additional Resources
|
|
||||||
|
|
||||||
- [OWASP Security Guidelines](https://owasp.org/www-project-top-ten/)
|
|
||||||
- [Helmet.js Documentation](https://helmetjs.github.io/)
|
|
||||||
- [JWT Security Best Practices](https://jwt.io/introduction)
|
|
||||||
|
|
||||||
## Getting Help
|
## Getting Help
|
||||||
|
|
||||||
If issues persist:
|
If you're still experiencing issues:
|
||||||
1. Review detailed logs.
|
|
||||||
2. Verify your configuration and environment.
|
|
||||||
3. Consult the GitHub issue tracker or community forums.
|
|
||||||
|
|
||||||
## FAQ
|
1. Check the [GitHub Issues](https://github.com/jango-blockchained/advanced-homeassistant-mcp/issues)
|
||||||
|
2. Search [Discussions](https://github.com/jango-blockchained/advanced-homeassistant-mcp/discussions)
|
||||||
### Q: How do I reset my configuration?
|
3. Create a new issue with:
|
||||||
A: Delete `.env` and copy `.env.example` to start fresh.
|
- Detailed description
|
||||||
|
|
||||||
### Q: Why are my events delayed?
|
|
||||||
A: Check network latency and server load. Consider adjusting buffer sizes.
|
|
||||||
|
|
||||||
### Q: How do I update my token?
|
|
||||||
A: Generate a new token in Home Assistant and update HASS_TOKEN.
|
|
||||||
|
|
||||||
### Q: Why do I get "Maximum clients reached"?
|
|
||||||
A: Adjust SSE_MAX_CLIENTS in configuration or clean up stale connections.
|
|
||||||
|
|
||||||
## Error Codes
|
|
||||||
|
|
||||||
- `E001`: Connection Error
|
|
||||||
- `E002`: Authentication Error
|
|
||||||
- `E003`: Rate Limit Error
|
|
||||||
- `E004`: Tool Error
|
|
||||||
- `E005`: Configuration Error
|
|
||||||
|
|
||||||
## Support Resources
|
|
||||||
|
|
||||||
1. Documentation
|
|
||||||
- [API Reference](./API.md)
|
|
||||||
- [Configuration Guide](./configuration/README.md)
|
|
||||||
- [Development Guide](./development/development.md)
|
|
||||||
|
|
||||||
2. Community
|
|
||||||
- GitHub Issues
|
|
||||||
- Discussion Forums
|
|
||||||
- Stack Overflow
|
|
||||||
|
|
||||||
3. Tools
|
|
||||||
- Diagnostic Scripts
|
|
||||||
- Testing Tools
|
|
||||||
- Monitoring Tools
|
|
||||||
|
|
||||||
## Still Need Help?
|
|
||||||
|
|
||||||
1. Create a detailed issue:
|
|
||||||
- Error messages
|
|
||||||
- Steps to reproduce
|
|
||||||
- Environment details
|
|
||||||
- Logs
|
- Logs
|
||||||
|
- Configuration (sanitized)
|
||||||
|
- Steps to reproduce
|
||||||
|
|
||||||
2. Contact support:
|
## Maintenance
|
||||||
- GitHub Issues
|
|
||||||
- Email Support
|
|
||||||
- Community Forums
|
|
||||||
|
|
||||||
## Security Middleware Troubleshooting
|
### Regular Health Checks
|
||||||
|
|
||||||
### Common Issues and Solutions
|
Run periodic health checks:
|
||||||
|
|
||||||
#### Rate Limiting Problems
|
```bash
|
||||||
|
# Create a cron job
|
||||||
|
*/5 * * * * curl -f http://localhost:3000/health || notify-admin
|
||||||
|
```
|
||||||
|
|
||||||
**Symptom**: Unexpected 429 (Too Many Requests) errors
|
### Log Rotation
|
||||||
|
|
||||||
**Possible Causes**:
|
Configure log rotation:
|
||||||
- Misconfigured rate limit settings
|
|
||||||
- Shared IP addresses (e.g., behind NAT)
|
|
||||||
- Aggressive client-side retry mechanisms
|
|
||||||
|
|
||||||
**Solutions**:
|
```yaml
|
||||||
1. Adjust rate limit parameters
|
logging:
|
||||||
```typescript
|
maxSize: "100m"
|
||||||
// Customize rate limit for specific scenarios
|
maxFiles: "7d"
|
||||||
checkRateLimit(ip, maxRequests = 200, windowMs = 30 * 60 * 1000)
|
compress: true
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Implement more granular rate limiting
|
### Backup Configuration
|
||||||
- Use different limits for different endpoints
|
|
||||||
- Consider user authentication level
|
|
||||||
|
|
||||||
#### Request Validation Failures
|
Regularly backup your configuration:
|
||||||
|
|
||||||
**Symptom**: 400 or 415 status codes on valid requests
|
```bash
|
||||||
|
# Backup script
|
||||||
**Possible Causes**:
|
tar -czf mcp-backup-$(date +%Y%m%d).tar.gz \
|
||||||
- Incorrect `Content-Type` header
|
.env \
|
||||||
- Large request payloads
|
config/ \
|
||||||
- Malformed authorization headers
|
data/
|
||||||
|
```
|
||||||
**Debugging Steps**:
|
|
||||||
1. Verify request headers
|
|
||||||
```typescript
|
|
||||||
// Check content type and size
|
|
||||||
validateRequestHeaders(request, 'application/json')
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Log detailed validation errors
|
|
||||||
```typescript
|
|
||||||
try {
|
|
||||||
validateRequestHeaders(request);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Request validation failed:', error.message);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Input Sanitization Issues
|
|
||||||
|
|
||||||
**Symptom**: Unexpected data transformation or loss
|
|
||||||
|
|
||||||
**Possible Causes**:
|
|
||||||
- Complex nested objects
|
|
||||||
- Non-standard input formats
|
|
||||||
- Overly aggressive sanitization
|
|
||||||
|
|
||||||
**Troubleshooting**:
|
|
||||||
1. Test sanitization with various input types
|
|
||||||
```typescript
|
|
||||||
const input = {
|
|
||||||
text: '<script>alert("xss")</script>',
|
|
||||||
nested: { html: '<img src="x" onerror="alert(1)">World' }
|
|
||||||
};
|
|
||||||
const sanitized = sanitizeValue(input);
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Custom sanitization for specific use cases
|
|
||||||
```typescript
|
|
||||||
function customSanitize(value) {
|
|
||||||
// Add custom sanitization logic
|
|
||||||
return sanitizeValue(value);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Security Header Configuration
|
|
||||||
|
|
||||||
**Symptom**: Missing or incorrect security headers
|
|
||||||
|
|
||||||
**Possible Causes**:
|
|
||||||
- Misconfigured Helmet options
|
|
||||||
- Environment-specific header requirements
|
|
||||||
|
|
||||||
**Solutions**:
|
|
||||||
1. Custom security header configuration
|
|
||||||
```typescript
|
|
||||||
const customHelmetConfig = {
|
|
||||||
contentSecurityPolicy: {
|
|
||||||
directives: {
|
|
||||||
defaultSrc: ["'self'"],
|
|
||||||
scriptSrc: ["'self'", 'trusted-cdn.com']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
applySecurityHeaders(request, customHelmetConfig);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Error Handling and Logging
|
|
||||||
|
|
||||||
**Symptom**: Inconsistent error responses
|
|
||||||
|
|
||||||
**Possible Causes**:
|
|
||||||
- Incorrect environment configuration
|
|
||||||
- Unhandled error types
|
|
||||||
|
|
||||||
**Debugging Techniques**:
|
|
||||||
1. Verify environment settings
|
|
||||||
```typescript
|
|
||||||
const errorResponse = handleError(error, process.env.NODE_ENV);
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Add custom error handling
|
|
||||||
```typescript
|
|
||||||
function enhancedErrorHandler(error, env) {
|
|
||||||
// Add custom logging or monitoring
|
|
||||||
console.error('Security error:', error);
|
|
||||||
return handleError(error, env);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Performance and Security Monitoring
|
|
||||||
|
|
||||||
1. **Logging**
|
|
||||||
- Enable debug logging for security events
|
|
||||||
- Monitor rate limit and validation logs
|
|
||||||
|
|
||||||
2. **Metrics**
|
|
||||||
- Track rate limit hit rates
|
|
||||||
- Monitor request validation success/failure ratios
|
|
||||||
|
|
||||||
3. **Continuous Improvement**
|
|
||||||
- Regularly review and update security configurations
|
|
||||||
- Conduct periodic security audits
|
|
||||||
|
|
||||||
### Environment-Specific Considerations
|
|
||||||
|
|
||||||
#### Development
|
|
||||||
- More verbose error messages
|
|
||||||
- Relaxed rate limiting
|
|
||||||
- Detailed security logs
|
|
||||||
|
|
||||||
#### Production
|
|
||||||
- Minimal error details
|
|
||||||
- Strict rate limiting
|
|
||||||
- Comprehensive security headers
|
|
||||||
|
|
||||||
### External Resources
|
|
||||||
|
|
||||||
- [OWASP Security Guidelines](https://owasp.org/www-project-top-ten/)
|
|
||||||
- [Helmet.js Documentation](https://helmetjs.github.io/)
|
|
||||||
- [JWT Security Best Practices](https://jwt.io/introduction)
|
|
||||||
|
|
||||||
### Getting Help
|
|
||||||
|
|
||||||
If you encounter persistent issues:
|
|
||||||
1. Check application logs
|
|
||||||
2. Verify environment configurations
|
|
||||||
3. Consult the project's issue tracker
|
|
||||||
4. Reach out to the development team with detailed error information
|
|
||||||
@@ -327,3 +327,7 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|||||||
echo -e "${GREEN}Home Assistant MCP test successful!${NC}"
|
echo -e "${GREEN}Home Assistant MCP test successful!${NC}"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# macOS environment configuration
|
||||||
|
HASS_SOCKET_URL="${HASS_HOST/http/ws}/api/websocket" # WebSocket URL conversion
|
||||||
|
chmod 600 "$CLAUDE_CONFIG_DIR/claude_desktop_config.json" # Security hardening
|
||||||
128
mkdocs.yml
128
mkdocs.yml
@@ -1,26 +1,138 @@
|
|||||||
site_name: Home Assistant Model Context Protocol (MCP)
|
site_name: Home Assistant MCP
|
||||||
site_url: https://yourusername.github.io/your-repo-name/
|
site_description: A bridge between Home Assistant and Language Learning Models
|
||||||
repo_url: https://github.com/yourusername/your-repo-name
|
site_url: https://jango-blockchained.github.io/advanced-homeassistant-mcp/
|
||||||
|
repo_url: https://github.com/jango-blockchained/advanced-homeassistant-mcp
|
||||||
|
repo_name: jango-blockchained/advanced-homeassistant-mcp
|
||||||
|
|
||||||
theme:
|
theme:
|
||||||
name: material
|
name: material
|
||||||
|
logo: assets/images/logo.png
|
||||||
|
favicon: assets/images/favicon.ico
|
||||||
|
palette:
|
||||||
|
- media: "(prefers-color-scheme: light)"
|
||||||
|
scheme: default
|
||||||
|
primary: indigo
|
||||||
|
accent: indigo
|
||||||
|
toggle:
|
||||||
|
icon: material/brightness-7
|
||||||
|
name: Switch to dark mode
|
||||||
|
- media: "(prefers-color-scheme: dark)"
|
||||||
|
scheme: slate
|
||||||
|
primary: indigo
|
||||||
|
accent: indigo
|
||||||
|
toggle:
|
||||||
|
icon: material/brightness-4
|
||||||
|
name: Switch to light mode
|
||||||
features:
|
features:
|
||||||
- navigation.tabs
|
- navigation.instant
|
||||||
|
- navigation.tracking
|
||||||
- navigation.sections
|
- navigation.sections
|
||||||
- toc.integrate
|
- navigation.expand
|
||||||
|
- navigation.top
|
||||||
- search.suggest
|
- search.suggest
|
||||||
- search.highlight
|
- search.highlight
|
||||||
|
- content.code.copy
|
||||||
|
|
||||||
markdown_extensions:
|
markdown_extensions:
|
||||||
- pymdownx.highlight
|
|
||||||
- pymdownx.superfences
|
|
||||||
- admonition
|
- admonition
|
||||||
|
- attr_list
|
||||||
|
- def_list
|
||||||
|
- footnotes
|
||||||
|
- meta
|
||||||
|
- toc:
|
||||||
|
permalink: true
|
||||||
|
- pymdownx.arithmatex:
|
||||||
|
generic: true
|
||||||
|
- pymdownx.betterem:
|
||||||
|
smart_enable: all
|
||||||
|
- pymdownx.caret
|
||||||
- pymdownx.details
|
- pymdownx.details
|
||||||
|
- pymdownx.emoji:
|
||||||
|
emoji_index: !!python/name:material.extensions.emoji.twemoji
|
||||||
|
emoji_generator: !!python/name:material.extensions.emoji.to_svg
|
||||||
|
- pymdownx.highlight:
|
||||||
|
anchor_linenums: true
|
||||||
|
- pymdownx.inlinehilite
|
||||||
|
- pymdownx.keys
|
||||||
|
- pymdownx.magiclink
|
||||||
|
- pymdownx.mark
|
||||||
|
- pymdownx.smartsymbols
|
||||||
|
- pymdownx.superfences:
|
||||||
|
custom_fences:
|
||||||
|
- name: mermaid
|
||||||
|
class: mermaid
|
||||||
|
format: !!python/name:pymdownx.superfences.fence_code_format
|
||||||
|
- pymdownx.tabbed:
|
||||||
|
alternate_style: true
|
||||||
|
- pymdownx.tasklist:
|
||||||
|
custom_checkbox: true
|
||||||
|
- pymdownx.tilde
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
- search
|
||||||
|
- git-revision-date-localized:
|
||||||
|
type: date
|
||||||
|
- mkdocstrings:
|
||||||
|
default_handler: python
|
||||||
|
handlers:
|
||||||
|
python:
|
||||||
|
options:
|
||||||
|
show_source: true
|
||||||
|
|
||||||
nav:
|
nav:
|
||||||
- Home: index.md
|
- Home: index.md
|
||||||
- Getting Started:
|
- Getting Started:
|
||||||
|
- Overview: getting-started.md
|
||||||
- Installation: getting-started/installation.md
|
- Installation: getting-started/installation.md
|
||||||
- Configuration: getting-started/configuration.md
|
- Configuration: getting-started/configuration.md
|
||||||
- Usage: usage.md
|
- Docker Setup: getting-started/docker.md
|
||||||
|
- Quick Start: getting-started/quickstart.md
|
||||||
|
- Usage: usage.md
|
||||||
|
- API Reference:
|
||||||
|
- Overview: api/index.md
|
||||||
|
- Core API: api.md
|
||||||
|
- SSE API: sse-api.md
|
||||||
|
- Core Functions: api/core.md
|
||||||
|
- Tools:
|
||||||
|
- Overview: tools/tools.md
|
||||||
|
- Device Management:
|
||||||
|
- List Devices: tools/device-management/list-devices.md
|
||||||
|
- Device Control: tools/device-management/control.md
|
||||||
|
- History & State:
|
||||||
|
- History: tools/history-state/history.md
|
||||||
|
- Scene Management: tools/history-state/scene.md
|
||||||
|
- Automation:
|
||||||
|
- Automation Management: tools/automation/automation.md
|
||||||
|
- Automation Configuration: tools/automation/automation-config.md
|
||||||
|
- Add-ons & Packages:
|
||||||
|
- Add-on Management: tools/addons-packages/addon.md
|
||||||
|
- Package Management: tools/addons-packages/package.md
|
||||||
|
- Notifications:
|
||||||
|
- Notify: tools/notifications/notify.md
|
||||||
|
- Events:
|
||||||
|
- Event Subscription: tools/events/subscribe-events.md
|
||||||
|
- SSE Statistics: tools/events/sse-stats.md
|
||||||
|
- Development:
|
||||||
|
- Overview: development/development.md
|
||||||
|
- Testing Guide: testing.md
|
||||||
|
- Architecture: architecture.md
|
||||||
- Contributing: contributing.md
|
- Contributing: contributing.md
|
||||||
|
- Troubleshooting: troubleshooting.md
|
||||||
|
- Examples:
|
||||||
|
- Overview: examples/index.md
|
||||||
|
- Roadmap: roadmap.md
|
||||||
|
|
||||||
|
extra:
|
||||||
|
social:
|
||||||
|
- icon: fontawesome/brands/github
|
||||||
|
link: https://github.com/jango-blockchained/homeassistant-mcp
|
||||||
|
- icon: fontawesome/brands/docker
|
||||||
|
link: https://hub.docker.com/r/jangoblockchained/homeassistant-mcp
|
||||||
|
analytics:
|
||||||
|
provider: google
|
||||||
|
property: !ENV GOOGLE_ANALYTICS_KEY
|
||||||
|
|
||||||
|
extra_css:
|
||||||
|
- assets/stylesheets/extra.css
|
||||||
|
|
||||||
|
copyright: Copyright © 2024 Jango Blockchained
|
||||||
@@ -21,7 +21,6 @@
|
|||||||
"profile": "bun --inspect src/index.ts",
|
"profile": "bun --inspect src/index.ts",
|
||||||
"clean": "rm -rf dist .bun coverage",
|
"clean": "rm -rf dist .bun coverage",
|
||||||
"typecheck": "bun x tsc --noEmit",
|
"typecheck": "bun x tsc --noEmit",
|
||||||
"preinstall": "bun install --frozen-lockfile",
|
|
||||||
"example:speech": "bun run examples/speech-to-text-example.ts"
|
"example:speech": "bun run examples/speech-to-text-example.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
21
scripts/start_mcp.cmd
Normal file
21
scripts/start_mcp.cmd
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
@echo off
|
||||||
|
setlocal
|
||||||
|
|
||||||
|
:: Set environment variables
|
||||||
|
set NODE_ENV=production
|
||||||
|
|
||||||
|
:: Change to the script's directory
|
||||||
|
cd /d "%~dp0"
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
:: Start the MCP server
|
||||||
|
echo Starting Home Assistant MCP Server...
|
||||||
|
bun run start --port 8080
|
||||||
|
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo Error starting MCP server
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
pause
|
||||||
@@ -18,4 +18,11 @@ startCommand:
|
|||||||
commandFunction:
|
commandFunction:
|
||||||
# A function that produces the CLI command to start the MCP on stdio.
|
# A function that produces the CLI command to start the MCP on stdio.
|
||||||
|-
|
|-
|
||||||
config => ({command: 'bun', args: ['--smol', 'run', 'start'], env: { HASS_TOKEN: config.hassToken, PORT: config.port.toString() }})
|
config => ({
|
||||||
|
command: 'bun',
|
||||||
|
args: ['--smol', 'run', 'start'],
|
||||||
|
env: {
|
||||||
|
HASS_TOKEN: config.hassToken,
|
||||||
|
PORT: config.port.toString()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ config({ path: resolve(process.cwd(), envFile) });
|
|||||||
*/
|
*/
|
||||||
export const AppConfigSchema = z.object({
|
export const AppConfigSchema = z.object({
|
||||||
/** Server Configuration */
|
/** Server Configuration */
|
||||||
PORT: z.number().default(4000),
|
PORT: z.coerce.number().default(4000),
|
||||||
NODE_ENV: z
|
NODE_ENV: z
|
||||||
.enum(["development", "production", "test"])
|
.enum(["development", "production", "test"])
|
||||||
.default("development"),
|
.default("development"),
|
||||||
|
|||||||
Reference in New Issue
Block a user