ha-mcp-dev 7.13.0.dev2005__tar.gz → 7.13.0.dev2009__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ha_mcp_dev-7.13.0.dev2005/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.13.0.dev2009}/PKG-INFO +1 -1
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/pyproject.toml +1 -10
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/client/rest_client.py +69 -19
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/component_api.py +9 -1
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/radio/matter.py +7 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/radio/zigbee.py +15 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/radio/zwave.py +14 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/reference_validator.py +58 -35
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_areas.py +205 -141
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_config_automations.py +63 -10
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_config_scenes.py +50 -16
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_config_scripts.py +64 -16
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_dev.py +141 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_history.py +83 -57
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_traces.py +99 -90
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_zones.py +67 -52
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/transforms/categorized_search.py +102 -79
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/visibility/resolver.py +151 -71
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/LICENSE +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/MANIFEST.in +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/README.md +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/setup.cfg +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/__main__.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/_pypi_marker +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/_version.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/auth/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/auth/consent_form.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/auth/provider.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/backup_manager.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/browser_landing.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/client/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/client/supervisor_client.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/client/websocket_client.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/client/websocket_listener.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/config.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/dashboard_screenshot/content.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/dashboard_screenshot/paths.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/dashboard_screenshot/theme_guard.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/errors.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/llm_exposure.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/policy/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/policy/approval_queue.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/policy/evaluator.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/policy/handlers.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/policy/middleware.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/policy/model.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/policy/persistence.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/policy/value_sources.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/py.typed +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/read_only.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/appdaemon.md +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/blueprint-guide.md +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/scenes.md +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/server.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/settings_ui/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/settings_ui/_handlers_advanced.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/settings_ui/_handlers_backups.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/settings_ui/_handlers_fs.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/settings_ui/_handlers_server.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/settings_ui/_handlers_theme.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/settings_ui/_handlers_tools.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/settings_ui/_i18n.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/settings_ui/_persistence.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/settings_ui/_supervisor.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/settings_ui/_theme.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/settings_ui/_tools_meta.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/settings_ui/locales/README.md +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/settings_ui/locales/de.json +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/settings_ui/locales/en.json +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/settings_ui/locales/ru.json +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/settings_ui/settings.css +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/settings_ui/settings.html +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/settings_ui/settings.js +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/smoke_test.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/strict_bps.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/auto_backup.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/backup.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/best_practice_checker.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/component_config_reads.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/component_devices.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/component_registries.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/component_registry_lookup.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/config_entry_flow.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/device_control.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/enhanced.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/helpers.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/radio/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/radio/base.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/radio/thread.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/registry.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/smart_search/_base.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/smart_search/_config.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tool_search_hint_middleware.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_addons.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_blueprints.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_bug_report.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_calendar.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_camera.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_categories.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_code.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_energy.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_entities.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_filesystem.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_groups.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_hacs.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_integrations.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_labels.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_radio.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_registry.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_resources.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_search.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_service.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_services.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_system.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_themes.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_todo.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_updates.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_utility.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/tools_yaml_read.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/util_helpers.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/validation_middleware.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/transforms/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/transport_security.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/update_check.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/utils/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/utils/config_hash.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/utils/data_paths.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/utils/domain_handlers.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/utils/fuzzy_search.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/utils/operation_manager.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/utils/python_sandbox.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/utils/skill_loader.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/utils/usage_logger.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/visibility/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/visibility/model.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/visibility/persistence.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/tests/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/tests/test_constants.py +0 -0
- {ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/tests/test_env_manager.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ha-mcp-dev"
|
|
7
|
-
version = "7.13.0.
|
|
7
|
+
version = "7.13.0.dev2009"
|
|
8
8
|
description = "Home Assistant MCP Server - Complete control of Home Assistant through MCP"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
# Upper bound widened to <3.15 so the package installs on Home Assistant's
|
|
@@ -178,21 +178,12 @@ ignore = [
|
|
|
178
178
|
"src/ha_mcp/backup_manager.py" = ["C901"]
|
|
179
179
|
"src/ha_mcp/tools/auto_backup.py" = ["C901"]
|
|
180
180
|
"src/ha_mcp/tools/backup.py" = ["C901"]
|
|
181
|
-
"src/ha_mcp/tools/radio/matter.py" = ["C901"]
|
|
182
|
-
"src/ha_mcp/tools/radio/zigbee.py" = ["C901"]
|
|
183
|
-
"src/ha_mcp/tools/radio/zwave.py" = ["C901"]
|
|
184
|
-
"src/ha_mcp/tools/reference_validator.py" = ["C901"]
|
|
185
|
-
"src/ha_mcp/tools/tools_areas.py" = ["C901"]
|
|
186
181
|
"src/ha_mcp/tools/tools_config_automations.py" = ["C901"]
|
|
187
182
|
"src/ha_mcp/tools/tools_config_scenes.py" = ["C901"]
|
|
188
183
|
"src/ha_mcp/tools/tools_config_scripts.py" = ["C901"]
|
|
189
184
|
"src/ha_mcp/tools/tools_dev.py" = ["C901"]
|
|
190
|
-
"src/ha_mcp/tools/tools_history.py" = ["C901"]
|
|
191
185
|
"src/ha_mcp/tools/tools_integrations.py" = ["C901"]
|
|
192
186
|
"src/ha_mcp/tools/tools_system.py" = ["C901"]
|
|
193
|
-
"src/ha_mcp/tools/tools_zones.py" = ["C901"]
|
|
194
|
-
"src/ha_mcp/transforms/categorized_search.py" = ["C901"]
|
|
195
|
-
"src/ha_mcp/visibility/resolver.py" = ["C901"]
|
|
196
187
|
"tests/src/e2e/conftest.py" = ["C901"]
|
|
197
188
|
"tests/src/e2e/error_handling/test_network_errors.py" = ["C901"]
|
|
198
189
|
"tests/src/e2e/policy/test_readonly_mode.py" = ["C901"]
|
|
@@ -975,7 +975,11 @@ class HomeAssistantClient:
|
|
|
975
975
|
raise
|
|
976
976
|
|
|
977
977
|
async def upsert_automation_config(
|
|
978
|
-
self,
|
|
978
|
+
self,
|
|
979
|
+
config: dict[str, Any],
|
|
980
|
+
identifier: str | None = None,
|
|
981
|
+
*,
|
|
982
|
+
_resolved: bool = False,
|
|
979
983
|
) -> dict[str, Any]:
|
|
980
984
|
"""
|
|
981
985
|
Create new automation or update existing one.
|
|
@@ -983,6 +987,12 @@ class HomeAssistantClient:
|
|
|
983
987
|
Args:
|
|
984
988
|
config: Automation configuration dictionary
|
|
985
989
|
identifier: Optional automation entity_id or unique_id (None = create new)
|
|
990
|
+
_resolved: When True, ``identifier`` is already the resolved unique_id
|
|
991
|
+
(the caller ran ``_resolve_automation_id``), so the redundant
|
|
992
|
+
entity_id→unique_id lookup is skipped. Ignored on the create path
|
|
993
|
+
(``identifier is None``). The #1404 config-id mismatch guard below
|
|
994
|
+
is unaffected — it still compares ``config['id']`` to the resolved
|
|
995
|
+
unique_id.
|
|
986
996
|
|
|
987
997
|
Returns:
|
|
988
998
|
Result with automation unique_id and status
|
|
@@ -996,7 +1006,11 @@ class HomeAssistantClient:
|
|
|
996
1006
|
operation = "created"
|
|
997
1007
|
logger.debug(f"Creating new automation with unique_id: {unique_id}")
|
|
998
1008
|
else:
|
|
999
|
-
unique_id =
|
|
1009
|
+
unique_id = (
|
|
1010
|
+
identifier
|
|
1011
|
+
if _resolved
|
|
1012
|
+
else await self._resolve_automation_id(identifier)
|
|
1013
|
+
)
|
|
1000
1014
|
operation = "updated"
|
|
1001
1015
|
logger.debug(f"Updating automation with unique_id: {unique_id}")
|
|
1002
1016
|
|
|
@@ -1592,14 +1606,33 @@ class HomeAssistantClient:
|
|
|
1592
1606
|
raise
|
|
1593
1607
|
|
|
1594
1608
|
async def upsert_script_config(
|
|
1595
|
-
self,
|
|
1609
|
+
self,
|
|
1610
|
+
config: dict[str, Any],
|
|
1611
|
+
script_id: str,
|
|
1612
|
+
*,
|
|
1613
|
+
resolved_id: str | None = None,
|
|
1596
1614
|
) -> dict[str, Any]:
|
|
1597
|
-
"""Create or update Home Assistant script configuration.
|
|
1598
|
-
|
|
1615
|
+
"""Create or update Home Assistant script configuration.
|
|
1616
|
+
|
|
1617
|
+
``resolved_id``, when provided, is the already-resolved storage key used
|
|
1618
|
+
as the write target (the caller ran :meth:`_resolve_script_id`),
|
|
1619
|
+
skipping the redundant entity-registry lookup. ``script_id`` stays the
|
|
1620
|
+
CALLER's identifier and is used only to default a missing ``alias`` — a
|
|
1621
|
+
renamed script (whose storage key differs from the entity slug the
|
|
1622
|
+
caller passed) keeps its caller-facing name rather than resetting the
|
|
1623
|
+
user-visible alias to the stale storage key (#1935).
|
|
1624
|
+
"""
|
|
1625
|
+
write_id = (
|
|
1626
|
+
resolved_id
|
|
1627
|
+
if resolved_id is not None
|
|
1628
|
+
else await self._resolve_script_id(script_id)
|
|
1629
|
+
)
|
|
1599
1630
|
try:
|
|
1600
|
-
endpoint = f"config/script/config/{
|
|
1631
|
+
endpoint = f"config/script/config/{write_id}"
|
|
1601
1632
|
|
|
1602
|
-
#
|
|
1633
|
+
# Default a missing alias from the CALLER's ``script_id`` (not
|
|
1634
|
+
# ``write_id``) so a renamed script's user-visible name is preserved
|
|
1635
|
+
# instead of being reset to the storage key.
|
|
1603
1636
|
if "alias" not in config:
|
|
1604
1637
|
config["alias"] = script_id
|
|
1605
1638
|
|
|
@@ -1614,7 +1647,7 @@ class HomeAssistantClient:
|
|
|
1614
1647
|
|
|
1615
1648
|
return {
|
|
1616
1649
|
"success": True,
|
|
1617
|
-
"script_id":
|
|
1650
|
+
"script_id": write_id,
|
|
1618
1651
|
"result": response.get("result", "ok"),
|
|
1619
1652
|
"operation": "created" if response.get("result") == "ok" else "updated",
|
|
1620
1653
|
}
|
|
@@ -1722,22 +1755,39 @@ class HomeAssistantClient:
|
|
|
1722
1755
|
raise
|
|
1723
1756
|
|
|
1724
1757
|
async def upsert_scene_config(
|
|
1725
|
-
self,
|
|
1758
|
+
self,
|
|
1759
|
+
config: dict[str, Any],
|
|
1760
|
+
scene_id: str,
|
|
1761
|
+
*,
|
|
1762
|
+
resolved_id: str | None = None,
|
|
1726
1763
|
) -> dict[str, Any]:
|
|
1727
1764
|
"""Create or update Home Assistant scene configuration.
|
|
1728
1765
|
|
|
1729
|
-
``
|
|
1730
|
-
|
|
1731
|
-
|
|
1766
|
+
``resolved_id``, when provided, is the already-resolved storage key used
|
|
1767
|
+
as the write target (the caller ran :meth:`resolve_scene_id`), skipping
|
|
1768
|
+
the redundant registry lookup. ``scene_id`` stays the CALLER's identifier
|
|
1769
|
+
and is used only to default a missing ``name`` — a renamed scene (whose
|
|
1770
|
+
storage key differs from the slug the caller passed) keeps its
|
|
1771
|
+
caller-facing name rather than resetting to the stale storage key
|
|
1772
|
+
(#1935, mirrors the script fix).
|
|
1732
1773
|
"""
|
|
1733
|
-
|
|
1774
|
+
write_id = (
|
|
1775
|
+
resolved_id
|
|
1776
|
+
if resolved_id is not None
|
|
1777
|
+
else await self.resolve_scene_id(scene_id)
|
|
1778
|
+
)
|
|
1734
1779
|
try:
|
|
1735
|
-
endpoint = f"config/scene/config/{
|
|
1736
|
-
|
|
1737
|
-
# Default a name when missing
|
|
1738
|
-
#
|
|
1780
|
+
endpoint = f"config/scene/config/{write_id}"
|
|
1781
|
+
|
|
1782
|
+
# Default a name when missing from the CALLER's ``scene_id`` (not
|
|
1783
|
+
# ``write_id``) — mirrors the script upsert behaviour so a bare
|
|
1784
|
+
# config dict is acceptable, without resetting a renamed scene's
|
|
1785
|
+
# name to the storage key. Strip the ``scene.`` prefix: a caller may
|
|
1786
|
+
# pass the entity_id form (``resolve_scene_id`` accepts it), and HA
|
|
1787
|
+
# derives the entity_id from the name slug — persisting the prefixed
|
|
1788
|
+
# form would rename the scene and change its entity_id on a plain update.
|
|
1739
1789
|
if "name" not in config:
|
|
1740
|
-
config["name"] = scene_id
|
|
1790
|
+
config["name"] = scene_id.removeprefix("scene.")
|
|
1741
1791
|
|
|
1742
1792
|
# Validate required field. ``entities`` is a dict keyed by entity_id,
|
|
1743
1793
|
# not a list — distinct from script ``sequence`` and automation ``action``.
|
|
@@ -1757,7 +1807,7 @@ class HomeAssistantClient:
|
|
|
1757
1807
|
# activity should diff before/after via ``ha_config_get_scene``.
|
|
1758
1808
|
return {
|
|
1759
1809
|
"success": True,
|
|
1760
|
-
"scene_id":
|
|
1810
|
+
"scene_id": write_id,
|
|
1761
1811
|
"result": response.get("result", "ok"),
|
|
1762
1812
|
}
|
|
1763
1813
|
except Exception as e:
|
|
@@ -273,9 +273,17 @@ async def get_component_caps(client: Any) -> ComponentCaps | None:
|
|
|
273
273
|
if not base_url or not token:
|
|
274
274
|
# Not a credentialed HA client — no WS connection to negotiate over.
|
|
275
275
|
return None
|
|
276
|
+
# Thread verify_ssl so a verify_ssl=False client keys (and can establish)
|
|
277
|
+
# its own pooled connection rather than failing the probe or colliding with
|
|
278
|
+
# a default-verification entry — otherwise EVERY component capability is
|
|
279
|
+
# silently unreachable on an HTTPS + verify_ssl=False install. ``None`` is
|
|
280
|
+
# the pool's settings default, so a client without the attr is unchanged.
|
|
281
|
+
verify_ssl = getattr(client, "verify_ssl", None)
|
|
276
282
|
|
|
277
283
|
try:
|
|
278
|
-
ws = await get_websocket_client(
|
|
284
|
+
ws = await get_websocket_client(
|
|
285
|
+
url=base_url, token=token, verify_ssl=verify_ssl
|
|
286
|
+
)
|
|
279
287
|
response = await ws.send_command(INFO_COMMAND)
|
|
280
288
|
except HomeAssistantCommandError:
|
|
281
289
|
# Old component (unknown_command) or an info handler bug: the
|
|
@@ -145,6 +145,13 @@ async def handle(client: Any, action: str, args: dict[str, Any]) -> dict[str, An
|
|
|
145
145
|
# Returns setup_pin_code, setup_manual_code, setup_qr_code.
|
|
146
146
|
return ok("matter", "share_out", commissioning=commissioning)
|
|
147
147
|
|
|
148
|
+
return await _handle_matter_more(client, action, args, device_id)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
async def _handle_matter_more(
|
|
152
|
+
client: Any, action: str, args: dict[str, Any], device_id: Any
|
|
153
|
+
) -> dict[str, Any]:
|
|
154
|
+
"""Continuation of :func:`handle` for the remaining Matter actions."""
|
|
148
155
|
if action == "interview":
|
|
149
156
|
result = await ws_call(
|
|
150
157
|
client,
|
|
@@ -272,6 +272,13 @@ async def handle(client: Any, action: str, args: dict[str, Any]) -> dict[str, An
|
|
|
272
272
|
long_running=True,
|
|
273
273
|
)
|
|
274
274
|
|
|
275
|
+
return await _handle_zigbee_groups(client, action, args, device_id)
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
async def _handle_zigbee_groups(
|
|
279
|
+
client: Any, action: str, args: dict[str, Any], device_id: Any
|
|
280
|
+
) -> dict[str, Any]:
|
|
281
|
+
"""Continuation of :func:`handle` for Zigbee group and binding actions."""
|
|
275
282
|
# --- groups ------------------------------------------------------------ #
|
|
276
283
|
if action == "group_add":
|
|
277
284
|
group = await ws_call(
|
|
@@ -340,6 +347,14 @@ async def handle(client: Any, action: str, args: dict[str, Any]) -> dict[str, An
|
|
|
340
347
|
)
|
|
341
348
|
return ok("zigbee", "unbind", result=result)
|
|
342
349
|
|
|
350
|
+
return await _handle_zigbee_clusters(client, action, args, device_id)
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
async def _handle_zigbee_clusters(
|
|
354
|
+
client: Any, action: str, args: dict[str, Any], device_id: Any
|
|
355
|
+
) -> dict[str, Any]:
|
|
356
|
+
"""Continuation of :func:`handle` for Zigbee cluster-write and network actions."""
|
|
357
|
+
cluster_type = args.get("cluster_type", "in")
|
|
343
358
|
# --- cluster writes (service-only) ------------------------------------- #
|
|
344
359
|
if action == "cluster_write":
|
|
345
360
|
ieee = await _resolve_ieee(client, device_id)
|
|
@@ -174,6 +174,13 @@ async def handle(client: Any, action: str, args: dict[str, Any]) -> dict[str, An
|
|
|
174
174
|
result = await client.call_service("zwave_js", "ping", {"device_id": device_id})
|
|
175
175
|
return ok("zwave", "ping", result=result)
|
|
176
176
|
|
|
177
|
+
return await _handle_zwave_inclusion(client, action, args, device_id)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
async def _handle_zwave_inclusion(
|
|
181
|
+
client: Any, action: str, args: dict[str, Any], device_id: Any
|
|
182
|
+
) -> dict[str, Any]:
|
|
183
|
+
"""Continuation of :func:`handle` for Z-Wave inclusion/exclusion actions."""
|
|
177
184
|
if action == "add":
|
|
178
185
|
entry_id = await _zwave_entry_id(client)
|
|
179
186
|
if not entry_id:
|
|
@@ -289,6 +296,13 @@ async def handle(client: Any, action: str, args: dict[str, Any]) -> dict[str, An
|
|
|
289
296
|
long_running=True,
|
|
290
297
|
)
|
|
291
298
|
|
|
299
|
+
return await _handle_zwave_maintenance(client, action, args, device_id)
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
async def _handle_zwave_maintenance(
|
|
303
|
+
client: Any, action: str, args: dict[str, Any], device_id: Any
|
|
304
|
+
) -> dict[str, Any]:
|
|
305
|
+
"""Continuation of :func:`handle` for Z-Wave node maintenance actions."""
|
|
292
306
|
if action == "reinterview":
|
|
293
307
|
result = await ws_call(
|
|
294
308
|
client,
|
{ha_mcp_dev-7.13.0.dev2005 → ha_mcp_dev-7.13.0.dev2009}/src/ha_mcp/tools/reference_validator.py
RENAMED
|
@@ -69,6 +69,55 @@ class ValidationWarning(TypedDict):
|
|
|
69
69
|
reason: str
|
|
70
70
|
|
|
71
71
|
|
|
72
|
+
def _extract_service_ref(
|
|
73
|
+
sub_path: str,
|
|
74
|
+
value: str,
|
|
75
|
+
refs: list[ExtractedRef],
|
|
76
|
+
unvalidated_templates: list[int],
|
|
77
|
+
) -> None:
|
|
78
|
+
"""Record a service ref at *sub_path*, counting templates instead."""
|
|
79
|
+
if _is_template(value):
|
|
80
|
+
unvalidated_templates[0] += 1
|
|
81
|
+
else:
|
|
82
|
+
refs.append({"path": sub_path, "value": value, "kind": "service"})
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _extract_entity_refs(
|
|
86
|
+
sub_path: str,
|
|
87
|
+
value: Any,
|
|
88
|
+
refs: list[ExtractedRef],
|
|
89
|
+
unvalidated_templates: list[int],
|
|
90
|
+
) -> bool:
|
|
91
|
+
"""Record entity ref(s) from a str or list *value*; return True if handled.
|
|
92
|
+
|
|
93
|
+
Returns False when *value* is neither a str nor a list so the caller can
|
|
94
|
+
keep recursing into it (an ``entity_id`` mapped to a nested structure).
|
|
95
|
+
"""
|
|
96
|
+
if isinstance(value, str):
|
|
97
|
+
if _is_template(value):
|
|
98
|
+
unvalidated_templates[0] += 1
|
|
99
|
+
else:
|
|
100
|
+
refs.append({"path": sub_path, "value": value, "kind": "entity"})
|
|
101
|
+
return True
|
|
102
|
+
if isinstance(value, list):
|
|
103
|
+
for i, item in enumerate(value):
|
|
104
|
+
if not isinstance(item, str):
|
|
105
|
+
continue
|
|
106
|
+
item_path = f"{sub_path}[{i}]"
|
|
107
|
+
if _is_template(item):
|
|
108
|
+
unvalidated_templates[0] += 1
|
|
109
|
+
else:
|
|
110
|
+
refs.append(
|
|
111
|
+
{
|
|
112
|
+
"path": item_path,
|
|
113
|
+
"value": item,
|
|
114
|
+
"kind": "entity",
|
|
115
|
+
}
|
|
116
|
+
)
|
|
117
|
+
return True
|
|
118
|
+
return False
|
|
119
|
+
|
|
120
|
+
|
|
72
121
|
def extract_refs(config: Any) -> WalkerResult:
|
|
73
122
|
"""Pull every literal service/entity reference out of *config*.
|
|
74
123
|
|
|
@@ -97,43 +146,17 @@ def extract_refs(config: Any) -> WalkerResult:
|
|
|
97
146
|
sub_path = f"{path}.{key}" if path else key
|
|
98
147
|
|
|
99
148
|
if key in _SERVICE_KEYS and isinstance(value, str):
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
149
|
+
_extract_service_ref(sub_path, value, refs, unvalidated_templates)
|
|
150
|
+
continue
|
|
151
|
+
|
|
152
|
+
if key in _ENTITY_KEYS and _extract_entity_refs(
|
|
153
|
+
sub_path, value, refs, unvalidated_templates
|
|
154
|
+
):
|
|
106
155
|
continue
|
|
107
156
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
unvalidated_templates[0] += 1
|
|
112
|
-
else:
|
|
113
|
-
refs.append(
|
|
114
|
-
{"path": sub_path, "value": value, "kind": "entity"}
|
|
115
|
-
)
|
|
116
|
-
continue
|
|
117
|
-
if isinstance(value, list):
|
|
118
|
-
for i, item in enumerate(value):
|
|
119
|
-
if not isinstance(item, str):
|
|
120
|
-
continue
|
|
121
|
-
item_path = f"{sub_path}[{i}]"
|
|
122
|
-
if _is_template(item):
|
|
123
|
-
unvalidated_templates[0] += 1
|
|
124
|
-
else:
|
|
125
|
-
refs.append(
|
|
126
|
-
{
|
|
127
|
-
"path": item_path,
|
|
128
|
-
"value": item,
|
|
129
|
-
"kind": "entity",
|
|
130
|
-
}
|
|
131
|
-
)
|
|
132
|
-
continue
|
|
133
|
-
|
|
134
|
-
# Neither a service nor an entity key: recurse so deeply
|
|
135
|
-
# nested action blocks (choose/if/parallel/repeat) still
|
|
136
|
-
# get walked.
|
|
157
|
+
# Neither a service nor an entity key (or an entity key whose
|
|
158
|
+
# value is neither str nor list): recurse so deeply nested
|
|
159
|
+
# action blocks (choose/if/parallel/repeat) still get walked.
|
|
137
160
|
_walk(value, sub_path)
|
|
138
161
|
|
|
139
162
|
elif isinstance(node, list):
|