dc4c5b7841
A `smarthome` block points Maven at a Home Assistant instance. She reads its entity states to answer "что включено дома?", and every controllable device becomes a PROPOSED row in the existing act allowlist — cmd ["smarthome",<entity_id>,<service>], scope smarthome:<domain> — so nothing new had to be invented for the mutating half. ProposeTool/EnableTool/DisableTool, tool.Matcher and the confirm turn are untouched; one branch in Executor.Exec routes such a row to the client instead of exec, and "smarthome" is never run as a binary. This is the same trick overnight/mcp-tools used for #251, on purpose. Discovery only ever PROPOSES, and every control row is destructive=true: there is no read-only way to turn the heating off, so flipping something in his flat always costs a confirm turn and always had to be enabled by hand on /tools, behind step-up. The entity and the service come from the row he enabled, never from the utterance — Exec drops the spoken tail for a house row. A router that misheard can pick the wrong lamp; it cannot compose a target of its own. The service is checked against the domain's table on the way out too, so a hand-edited cmd column cannot reach an arbitrary Home Assistant service. set_brightness and set_temperature are deliberately absent: a spoken number the router got wrong is a wrong act on real hardware, and on/off is the whole of what a voice turn can defend. The read side is a query source ("home", before calendar and the recall passes) so "что нового дома?" is not answered from an old note. Its matcher needs a house marker plus an ask plus a device word and bails out on weather wording, because "какая температура на улице?" belongs to the weather source. Off unless configured: the block is dark without "enabled": true, and applyDefaults normalises a disabled block to nil so "off" stays in one place. deploy/mavend.json carries it disabled, with the token as ${HA_TOKEN}. NOT shipped, and not faked: MQTT / Zigbee2MQTT (plan steps 2 and 5) and the sensor-to-fact and presence-probe pipelines. There is no broker and no Home Assistant anywhere on this network — 8123 and 1883 are closed on every host in 192.168.1.0/24 — the module tree is vendored so a paho dependency cannot be added offline, and Home Assistant already fronts Zigbee2MQTT where it exists. Writing a sensor pipeline with no sensor to test it against would be a guess. Vikunja #256
95 lines
3.3 KiB
JSON
95 lines
3.3 KiB
JSON
{
|
|
"db_path": "/var/lib/maven/maven.db.enc",
|
|
"db_tmpfs": "/dev/shm/maven-plain.db",
|
|
"db_key_env": "MAVEN_DB_KEY",
|
|
"socket_path": "/run/maven/mavend.sock",
|
|
"state_dir": "/var/lib/maven",
|
|
|
|
"phraser": {
|
|
"model_path": "/opt/maven/models/llm/qwen3/Qwen3-1.7B-UD-Q4_K_XL.gguf",
|
|
"bin_path": "llama-server",
|
|
"n_gpu_layers": 99,
|
|
"n_ctx": 4096,
|
|
"timeout": "60s",
|
|
"llm_nudges": false
|
|
},
|
|
|
|
"telegram": {
|
|
"bot_token": "${TELEGRAM_BOT_TOKEN}",
|
|
"chat_id": "${TELEGRAM_CHAT_ID}"
|
|
},
|
|
|
|
"digest": {
|
|
"enabled": true,
|
|
"window": "30m",
|
|
"max_items": 5,
|
|
"severity_ceiling": 2
|
|
},
|
|
|
|
"pattern_proposals": {
|
|
"notify": false,
|
|
"cooldown": "24h"
|
|
},
|
|
|
|
"mcp": {
|
|
"timeout": "15s",
|
|
"servers": [
|
|
{
|
|
"name": "vikunja",
|
|
"url": "http://192.168.1.104:9100/mcp",
|
|
"allow_private": true,
|
|
"allow_tools": ["list_projects", "list_tasks", "get_task_details", "create_task"],
|
|
"max_tools": 6,
|
|
"enabled": false
|
|
}
|
|
]
|
|
},
|
|
|
|
"smarthome": {
|
|
"provider": "homeassistant",
|
|
"url": "http://192.168.1.50:8123",
|
|
"token": "${HA_TOKEN}",
|
|
"domains": ["light", "switch", "sensor"],
|
|
"max_entities": 40,
|
|
"timeout": "10s",
|
|
"refresh": "15m",
|
|
"enabled": false
|
|
},
|
|
|
|
"nexus": { "url": "http://nexus:9740" },
|
|
"praxis": { "url": "http://praxis:8989" },
|
|
"hexis": { "url": "http://hexis:9741" },
|
|
|
|
"voice": {
|
|
"enabled": true,
|
|
"bind": "0.0.0.0:9100",
|
|
"lang": "ru",
|
|
"stt": { "socket": "/run/maven/stt.sock", "lang": "ru" },
|
|
"tts": { "socket": "/run/maven/tts.sock", "lang": "ru" },
|
|
"embedder": {
|
|
"model_path": "/opt/maven/models/embedder/multilingual-e5-small/model_quantized.onnx",
|
|
"tokenizer_path": "/opt/maven/models/embedder/multilingual-e5-small/tokenizer.json",
|
|
"lib_path": "/opt/maven/lib/libonnxruntime.so"
|
|
},
|
|
"llm_router": true,
|
|
"query_min_score": 0.55,
|
|
"query_min_margin": 0.008,
|
|
"clarify_max_attempts": 3,
|
|
"tool_timeout": "30s",
|
|
"tools": [
|
|
{ "name": "status", "cmd": ["systemctl", "status"], "scope": "homelab", "destructive": false },
|
|
{ "name": "ps", "cmd": ["docker", "ps"], "scope": "homelab", "destructive": false },
|
|
{ "name": "uptime", "cmd": ["uptime"], "scope": "homelab", "destructive": false },
|
|
{ "name": "disk", "cmd": ["df", "-h"], "scope": "homelab", "destructive": false },
|
|
{ "name": "memory", "cmd": ["free", "-h"], "scope": "homelab", "destructive": false },
|
|
{ "name": "logs", "cmd": ["journalctl", "-n", "50", "-u"], "scope": "homelab", "destructive": false },
|
|
{ "name": "restart", "cmd": ["systemctl", "restart"], "scope": "homelab", "destructive": true },
|
|
{ "name": "stop", "cmd": ["systemctl", "stop"], "scope": "homelab", "destructive": true },
|
|
{ "name": "start", "cmd": ["systemctl", "start"], "scope": "homelab", "destructive": true },
|
|
{ "name": "docker-restart", "cmd": ["docker", "restart"], "scope": "homelab", "destructive": true },
|
|
{ "name": "docker-stop", "cmd": ["docker", "stop"], "scope": "homelab", "destructive": true },
|
|
{ "name": "reboot", "cmd": ["systemctl", "reboot"], "scope": "homelab", "destructive": true }
|
|
]
|
|
}
|
|
}
|