ha-mcp-dev 7.6.0.dev677__tar.gz → 7.7.0.dev681__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.6.0.dev677/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.7.0.dev681}/PKG-INFO +1 -1
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/pyproject.toml +1 -1
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_integrations.py +77 -57
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/tests/test_constants.py +1 -1
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/LICENSE +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/MANIFEST.in +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/README.md +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/setup.cfg +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/__main__.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/_pypi_marker +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/_version.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/auth/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/auth/consent_form.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/auth/provider.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/backup_manager.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/client/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/client/rest_client.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/client/supervisor_client.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/client/websocket_client.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/client/websocket_listener.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/config.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/errors.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/policy/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/policy/approval_queue.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/policy/evaluator.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/policy/handlers.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/policy/middleware.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/policy/model.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/policy/persistence.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/policy/value_sources.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/py.typed +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/server.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/settings.css +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/settings.js +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/settings_ui.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/smoke_test.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/auto_backup.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/backup.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/best_practice_checker.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/device_control.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/enhanced.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/helpers.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/reference_validator.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/registry.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/smart_search/_base.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/smart_search/_config.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_addons.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_areas.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_blueprints.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_bug_report.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_calendar.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_camera.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_categories.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_code.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_config_automations.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_config_entry_flow.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_energy.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_entities.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_filesystem.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_groups.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_hacs.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_history.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_labels.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_registry.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_resources.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_search.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_service.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_services.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_system.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_todo.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_traces.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_updates.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_utility.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_zones.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/util_helpers.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/validation_middleware.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/transforms/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/transforms/categorized_search.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/utils/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/utils/config_hash.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/utils/data_paths.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/utils/domain_handlers.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/utils/fuzzy_search.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/utils/operation_manager.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/utils/python_sandbox.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/utils/skill_loader.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/utils/usage_logger.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/tests/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/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.
|
|
7
|
+
version = "7.7.0.dev681"
|
|
8
8
|
description = "Home Assistant MCP Server - Complete control of Home Assistant through MCP"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.13,<3.14"
|
|
@@ -102,13 +102,18 @@ assert set(get_args(HelperTypeLiteral)) == (
|
|
|
102
102
|
def options_from_form_flow(flow: dict[str, Any]) -> dict[str, Any]:
|
|
103
103
|
"""Extract ``{field_name: current_value}`` from a form-type OptionsFlow.
|
|
104
104
|
|
|
105
|
-
Reads each ``data_schema`` entry's ``
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
``
|
|
111
|
-
|
|
105
|
+
Reads each ``data_schema`` entry's ``description.suggested_value``
|
|
106
|
+
first: HA's ``add_suggested_values_to_schema`` injects the entry's
|
|
107
|
+
*persisted* option there (voluptuous renders ``suggested_value=...``
|
|
108
|
+
into the ``description`` sub-object, not as a top-level field key),
|
|
109
|
+
and it is what the HA UI renders as the current value. Falls back to
|
|
110
|
+
``default`` (the static schema default a brand-new form would show)
|
|
111
|
+
and then ``value`` (constant-type fields ship ``value`` instead of
|
|
112
|
+
``default``). A field can carry both ``suggested_value`` and
|
|
113
|
+
``default`` at once — e.g. a group helper's ``hide_members`` stored as
|
|
114
|
+
``True`` over a schema default of ``False`` — and the stored value
|
|
115
|
+
must win (issue #1575). Fields with a missing or ``None`` value are
|
|
116
|
+
skipped.
|
|
112
117
|
"""
|
|
113
118
|
out: dict[str, Any] = {}
|
|
114
119
|
# Defensive: HA should always return a list of dict fields, but guard
|
|
@@ -123,11 +128,12 @@ def options_from_form_flow(flow: dict[str, Any]) -> dict[str, Any]:
|
|
|
123
128
|
name = field.get("name")
|
|
124
129
|
if name is None:
|
|
125
130
|
continue
|
|
126
|
-
value =
|
|
131
|
+
value = None
|
|
132
|
+
description = field.get("description")
|
|
133
|
+
if isinstance(description, dict):
|
|
134
|
+
value = description.get("suggested_value")
|
|
127
135
|
if value is None:
|
|
128
|
-
|
|
129
|
-
if isinstance(description, dict):
|
|
130
|
-
value = description.get("suggested_value")
|
|
136
|
+
value = field.get("default", field.get("value"))
|
|
131
137
|
if value is not None:
|
|
132
138
|
out[name] = value
|
|
133
139
|
return out
|
|
@@ -138,7 +144,10 @@ async def fetch_entry_options_with_status(
|
|
|
138
144
|
) -> tuple[dict[str, Any], bool]:
|
|
139
145
|
"""Read a config entry's ``options`` and report whether the probe succeeded.
|
|
140
146
|
|
|
141
|
-
|
|
147
|
+
Starts the entry's OptionsFlow, harvests ``{name: current_value}`` from
|
|
148
|
+
its first-step form via :func:`options_from_form_flow` (the persisted
|
|
149
|
+
option from ``description.suggested_value``, falling back to the schema
|
|
150
|
+
``default``), and aborts the flow so it doesn't sit half-open. Returns
|
|
142
151
|
``(options, ok)`` so callers can tell a probe *failure* apart from a
|
|
143
152
|
genuinely-empty options form — both yield ``{}`` for ``options``, but
|
|
144
153
|
``ok`` is:
|
|
@@ -147,20 +156,23 @@ async def fetch_entry_options_with_status(
|
|
|
147
156
|
fields: a genuinely-empty options form is a successful read).
|
|
148
157
|
- ``False`` when the OptionsFlow could not be read into options: the flow
|
|
149
158
|
raised, or its first step was not a form (a menu / abort / create_entry),
|
|
150
|
-
so no
|
|
159
|
+
so no options could be harvested.
|
|
151
160
|
|
|
152
|
-
The flag lets
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
failed abort does not flip ``ok`` (the options were
|
|
161
|
+
The flag lets callers surface degraded reads instead of passing ``{}``
|
|
162
|
+
off as real options: ``smart_search`` flips ``partial`` when a probe
|
|
163
|
+
fails mid-search, and ``ha_get_integration`` attaches a ``warnings``
|
|
164
|
+
entry on its single-entry and list responses. The abort in ``finally``
|
|
165
|
+
is cleanup; a failed abort does not flip ``ok`` (the options were
|
|
166
|
+
already harvested).
|
|
157
167
|
|
|
158
168
|
Home Assistant does not expose ``ConfigEntry.options`` through any
|
|
159
169
|
read-only REST or WebSocket endpoint — ``/api/config/config_entries/entry``
|
|
160
170
|
deliberately omits the field. The closest approximation that the HA UI
|
|
161
|
-
itself uses is the
|
|
162
|
-
|
|
163
|
-
|
|
171
|
+
itself uses is the OptionsFlow's first-step ``data_schema``: HA injects
|
|
172
|
+
the persisted options into each field's ``description.suggested_value``
|
|
173
|
+
(via ``add_suggested_values_to_schema``), which
|
|
174
|
+
:func:`options_from_form_flow` prefers over the static schema
|
|
175
|
+
``default`` (issue #1575).
|
|
164
176
|
|
|
165
177
|
Probe failures log at ``warning`` (so breakage of a deliberate
|
|
166
178
|
single-entry probe is discoverable) unless ``quiet=True``, which demotes
|
|
@@ -181,7 +193,7 @@ async def fetch_entry_options_with_status(
|
|
|
181
193
|
if flow_type != "form":
|
|
182
194
|
log_probe_failure(
|
|
183
195
|
f"OptionsFlow for {entry_id} returned type={flow_type!r}, "
|
|
184
|
-
f"not a form — cannot extract
|
|
196
|
+
f"not a form — cannot extract options"
|
|
185
197
|
)
|
|
186
198
|
return {}, False
|
|
187
199
|
return options_from_form_flow(flow), True
|
|
@@ -201,25 +213,6 @@ async def fetch_entry_options_with_status(
|
|
|
201
213
|
)
|
|
202
214
|
|
|
203
215
|
|
|
204
|
-
async def fetch_entry_options(
|
|
205
|
-
client: Any, entry_id: str, *, quiet: bool = False
|
|
206
|
-
) -> dict[str, Any]:
|
|
207
|
-
"""Read the current ``options`` for a config entry via its OptionsFlow.
|
|
208
|
-
|
|
209
|
-
Starts the flow, harvests ``{name: default}`` from the first step, and
|
|
210
|
-
aborts the flow so it doesn't sit half-open. Returns ``{}`` on any failure
|
|
211
|
-
(unsupported entry, non-form first step such as a menu, init/abort errors)
|
|
212
|
-
so callers can treat the return as the canonical "options" field without
|
|
213
|
-
further checks.
|
|
214
|
-
|
|
215
|
-
Thin wrapper over :func:`fetch_entry_options_with_status` for callers that
|
|
216
|
-
only need the options dict and not the success flag (e.g. the
|
|
217
|
-
``ha_remove_helpers_integrations`` / ``ha_get_integration`` config readout).
|
|
218
|
-
"""
|
|
219
|
-
options, _ok = await fetch_entry_options_with_status(client, entry_id, quiet=quiet)
|
|
220
|
-
return options
|
|
221
|
-
|
|
222
|
-
|
|
223
216
|
async def _get_entry_id_for_flow_helper(
|
|
224
217
|
client: Any,
|
|
225
218
|
helper_type: str,
|
|
@@ -714,19 +707,33 @@ class IntegrationTools:
|
|
|
714
707
|
|
|
715
708
|
# Surface `options` on every per-entry response (HA's REST endpoint
|
|
716
709
|
# omits the field). For entries with supports_options=True we probe
|
|
717
|
-
# via OptionsFlow — see `
|
|
718
|
-
# is also requested, `_fetch_options_schema` below
|
|
719
|
-
# from the same flow init so we don't pay for
|
|
710
|
+
# via OptionsFlow — see `fetch_entry_options_with_status`. When
|
|
711
|
+
# include_schema is also requested, `_fetch_options_schema` below
|
|
712
|
+
# populates options from the same flow init so we don't pay for
|
|
713
|
+
# two round-trips.
|
|
714
|
+
probe_warnings: list[str] = []
|
|
720
715
|
if isinstance(result, dict):
|
|
721
716
|
result.setdefault("options", {})
|
|
722
717
|
if result.get("supports_options") and not include_schema:
|
|
723
|
-
|
|
718
|
+
options, probe_ok = await fetch_entry_options_with_status(
|
|
719
|
+
self._client, entry_id
|
|
720
|
+
)
|
|
721
|
+
result["options"] = options
|
|
722
|
+
if not probe_ok:
|
|
723
|
+
probe_warnings.append(
|
|
724
|
+
f"options probe failed for {entry_id}: the "
|
|
725
|
+
"OptionsFlow could not be read, so 'options' may "
|
|
726
|
+
"be incomplete — empty options does not mean the "
|
|
727
|
+
"entry has none"
|
|
728
|
+
)
|
|
724
729
|
|
|
725
730
|
resp: dict[str, Any] = {
|
|
726
731
|
"success": True,
|
|
727
732
|
"entry_id": entry_id,
|
|
728
733
|
"entry": result,
|
|
729
734
|
}
|
|
735
|
+
if probe_warnings:
|
|
736
|
+
resp["warnings"] = probe_warnings
|
|
730
737
|
|
|
731
738
|
# Surface the effective Python logger level for this integration
|
|
732
739
|
# so users can confirm logger.set_level changes took effect.
|
|
@@ -862,15 +869,6 @@ class IntegrationTools:
|
|
|
862
869
|
"""Class-method alias for :func:`options_from_form_flow`."""
|
|
863
870
|
return options_from_form_flow(flow)
|
|
864
871
|
|
|
865
|
-
async def _fetch_entry_options(self, entry_id: str) -> dict[str, Any]:
|
|
866
|
-
"""Instance wrapper around :func:`fetch_entry_options`.
|
|
867
|
-
|
|
868
|
-
Kept so existing call sites (and the ``include_schema`` path) read
|
|
869
|
-
naturally as ``self._fetch_entry_options(...)``; the probe logic and
|
|
870
|
-
full rationale live on the module-level function.
|
|
871
|
-
"""
|
|
872
|
-
return await fetch_entry_options(self._client, entry_id)
|
|
873
|
-
|
|
874
872
|
async def _fetch_options_schema(self, entry_id: str, resp: dict[str, Any]) -> None:
|
|
875
873
|
"""Start an options flow to read the schema, then abort it.
|
|
876
874
|
|
|
@@ -903,6 +901,12 @@ class IntegrationTools:
|
|
|
903
901
|
f"Failed to fetch options schema for {entry_id}: "
|
|
904
902
|
f"{type(schema_err).__name__}: {schema_err}"
|
|
905
903
|
)
|
|
904
|
+
schema_warnings: list[str] = resp.setdefault("warnings", [])
|
|
905
|
+
schema_warnings.append(
|
|
906
|
+
f"options schema probe failed for {entry_id}: "
|
|
907
|
+
f"{type(schema_err).__name__} — 'options_schema' is missing "
|
|
908
|
+
"and 'options' may be incomplete"
|
|
909
|
+
)
|
|
906
910
|
finally:
|
|
907
911
|
if flow_id:
|
|
908
912
|
try:
|
|
@@ -949,11 +953,14 @@ class IntegrationTools:
|
|
|
949
953
|
|
|
950
954
|
# `_format_entry` is sync and cannot probe the OptionsFlow; options
|
|
951
955
|
# are filled in by a second async pass below for entries that
|
|
952
|
-
# advertise supports_options=True. See `
|
|
956
|
+
# advertise supports_options=True. See `fetch_entry_options_with_status`.
|
|
953
957
|
formatted_entries = [
|
|
954
958
|
self._format_entry(entry, include_opts, logger_levels) for entry in entries
|
|
955
959
|
]
|
|
956
960
|
|
|
961
|
+
# quiet=True: per-entry probe failures are aggregated into a response
|
|
962
|
+
# warning below instead of one log line each (bulk fan-out).
|
|
963
|
+
probe_failures: list[str] = []
|
|
957
964
|
if include_opts:
|
|
958
965
|
options_targets = [
|
|
959
966
|
e for e in formatted_entries if e.get("supports_options")
|
|
@@ -961,13 +968,19 @@ class IntegrationTools:
|
|
|
961
968
|
if options_targets:
|
|
962
969
|
fetched = await asyncio.gather(
|
|
963
970
|
*(
|
|
964
|
-
|
|
971
|
+
fetch_entry_options_with_status(
|
|
972
|
+
self._client, e["entry_id"], quiet=True
|
|
973
|
+
)
|
|
965
974
|
for e in options_targets
|
|
966
975
|
),
|
|
967
976
|
return_exceptions=False,
|
|
968
977
|
)
|
|
969
|
-
for entry, opts in zip(
|
|
978
|
+
for entry, (opts, probe_ok) in zip(
|
|
979
|
+
options_targets, fetched, strict=True
|
|
980
|
+
):
|
|
970
981
|
entry["options"] = opts
|
|
982
|
+
if not probe_ok:
|
|
983
|
+
probe_failures.append(entry["entry_id"])
|
|
971
984
|
|
|
972
985
|
# Apply search filter if query provided
|
|
973
986
|
if query and query.strip():
|
|
@@ -996,6 +1009,13 @@ class IntegrationTools:
|
|
|
996
1009
|
}
|
|
997
1010
|
if domain:
|
|
998
1011
|
result_data["domain_filter"] = domain.strip().lower()
|
|
1012
|
+
if probe_failures:
|
|
1013
|
+
result_data["warnings"] = [
|
|
1014
|
+
f"options probe failed for {len(probe_failures)} "
|
|
1015
|
+
f"entr{'y' if len(probe_failures) == 1 else 'ies'} "
|
|
1016
|
+
f"({', '.join(probe_failures)}) — their 'options' may be "
|
|
1017
|
+
"incomplete; empty options does not mean an entry has none"
|
|
1018
|
+
]
|
|
999
1019
|
return result_data
|
|
1000
1020
|
|
|
1001
1021
|
@staticmethod
|
|
@@ -20,7 +20,7 @@ NON_ADMIN_TEST_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIzNzkyOTc
|
|
|
20
20
|
# Home Assistant Docker image for E2E/performance/UAT tests.
|
|
21
21
|
# Keep in sync with .github/workflows/e2e-tests.yml and pr.yml.
|
|
22
22
|
# renovate: datasource=docker depName=ghcr.io/home-assistant/home-assistant
|
|
23
|
-
HA_TEST_IMAGE = "ghcr.io/home-assistant/home-assistant:2026.
|
|
23
|
+
HA_TEST_IMAGE = "ghcr.io/home-assistant/home-assistant:2026.6.1"
|
|
24
24
|
|
|
25
25
|
# Test user credentials (for UI access)
|
|
26
26
|
TEST_USER = "mcp"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/dashboard_screenshot/__init__.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/dashboard_screenshot/capture.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/dashboard_screenshot/provision.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/AGENTS.md
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/CLAUDE.md
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/LICENSE
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/resources/skills-vendor/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/best_practice_checker.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/smart_search/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/smart_search/_config.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/smart_search/_entities.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/smart_search/_overview.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/smart_search/_scenes.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/smart_search/_scoring.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_config_automations.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_config_dashboards.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_config_entry_flow.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_config_helpers.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_config_scripts.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_dashboard_screenshot.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/tools_voice_assistant.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/tools/validation_middleware.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/transforms/categorized_search.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/transforms/lite_docstrings.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp/utils/kill_signal_diagnostics.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp_dev.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev677 → ha_mcp_dev-7.7.0.dev681}/src/ha_mcp_dev.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|