ha-mcp-dev 7.5.0.dev540__tar.gz → 7.5.0.dev542__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.5.0.dev540/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.5.0.dev542}/PKG-INFO +3 -3
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/README.md +2 -2
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/pyproject.toml +1 -1
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_integrations.py +187 -2
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_system.py +144 -6
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/util_helpers.py +378 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542/src/ha_mcp_dev.egg-info}/PKG-INFO +3 -3
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/LICENSE +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/MANIFEST.in +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/setup.cfg +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/__init__.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/__main__.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/_pypi_marker +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/_version.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/auth/__init__.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/auth/consent_form.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/auth/provider.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/client/__init__.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/client/rest_client.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/client/supervisor_client.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/client/websocket_client.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/client/websocket_listener.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/config.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/errors.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/py.typed +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/server.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/settings_ui.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/smoke_test.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/__init__.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/backup.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/best_practice_checker.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/device_control.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/enhanced.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/helpers.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/reference_validator.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/registry.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/smart_search.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_addons.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_areas.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_blueprints.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_bug_report.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_calendar.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_camera.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_categories.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_code.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_config_automations.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_config_entry_flow.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_energy.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_entities.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_filesystem.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_groups.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_hacs.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_history.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_labels.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_registry.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_resources.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_search.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_service.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_services.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_todo.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_traces.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_updates.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_utility.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/tools/tools_zones.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/transforms/__init__.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/transforms/categorized_search.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/utils/__init__.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/utils/config_hash.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/utils/data_paths.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/utils/domain_handlers.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/utils/fuzzy_search.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/utils/operation_manager.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/utils/python_sandbox.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp/utils/usage_logger.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/tests/__init__.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/tests/test_constants.py +0 -0
- {ha_mcp_dev-7.5.0.dev540 → ha_mcp_dev-7.5.0.dev542}/tests/test_env_manager.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ha-mcp-dev
|
|
3
|
-
Version: 7.5.0.
|
|
3
|
+
Version: 7.5.0.dev542
|
|
4
4
|
Summary: Home Assistant MCP Server - Complete control of Home Assistant through MCP
|
|
5
5
|
Author-email: Julien <github@qc-h.net>
|
|
6
6
|
License: MIT
|
|
@@ -200,13 +200,13 @@ Spend less time configuring, more time enjoying your smart home.
|
|
|
200
200
|
| **HACS** | `ha_hacs_add_repository`, `ha_hacs_download`, `ha_hacs_repository_info`, `ha_hacs_search` |
|
|
201
201
|
| **Helper Entities** | `ha_config_list_helpers`, `ha_config_set_helper`, `ha_delete_helpers_integrations` |
|
|
202
202
|
| **History & Statistics** | `ha_get_automation_traces`, `ha_get_history`, `ha_get_logs` |
|
|
203
|
-
| **Integrations** | `ha_get_integration`, `ha_set_integration_enabled` |
|
|
203
|
+
| **Integrations** | `ha_get_integration`, `ha_get_system_health`, `ha_set_integration_enabled` |
|
|
204
204
|
| **Labels & Categories** | `ha_config_get_category`, `ha_config_get_label`, `ha_config_remove_category`, `ha_config_remove_label`, `ha_config_set_category`, `ha_config_set_label` |
|
|
205
205
|
| **Scenes** | `ha_config_get_scene`, `ha_config_remove_scene`, `ha_config_set_scene` |
|
|
206
206
|
| **Scripts** | `ha_config_get_script`, `ha_config_remove_script`, `ha_config_set_script` |
|
|
207
207
|
| **Search & Discovery** | `ha_deep_search`, `ha_get_overview`, `ha_get_state`, `ha_search_entities` |
|
|
208
208
|
| **Service & Device Control** | `ha_bulk_control`, `ha_call_event`, `ha_call_service`, `ha_get_operation_status`, `ha_list_services` |
|
|
209
|
-
| **System** | `ha_backup_create`, `ha_backup_restore`, `ha_check_config`, `ha_config_set_yaml` *(beta)*, `
|
|
209
|
+
| **System** | `ha_backup_create`, `ha_backup_restore`, `ha_check_config`, `ha_config_set_yaml` *(beta)*, `ha_get_updates`, `ha_manage_custom_tool` *(beta)*, `ha_reload_core`, `ha_restart` |
|
|
210
210
|
| **Todo Lists** | `ha_get_todo`, `ha_remove_todo_item`, `ha_set_todo_item` |
|
|
211
211
|
| **Utilities** | `ha_eval_template`, `ha_install_mcp_tools` *(beta)*, `ha_report_issue` |
|
|
212
212
|
| **Zones** | `ha_get_zone`, `ha_remove_zone`, `ha_set_zone` |
|
|
@@ -170,13 +170,13 @@ Spend less time configuring, more time enjoying your smart home.
|
|
|
170
170
|
| **HACS** | `ha_hacs_add_repository`, `ha_hacs_download`, `ha_hacs_repository_info`, `ha_hacs_search` |
|
|
171
171
|
| **Helper Entities** | `ha_config_list_helpers`, `ha_config_set_helper`, `ha_delete_helpers_integrations` |
|
|
172
172
|
| **History & Statistics** | `ha_get_automation_traces`, `ha_get_history`, `ha_get_logs` |
|
|
173
|
-
| **Integrations** | `ha_get_integration`, `ha_set_integration_enabled` |
|
|
173
|
+
| **Integrations** | `ha_get_integration`, `ha_get_system_health`, `ha_set_integration_enabled` |
|
|
174
174
|
| **Labels & Categories** | `ha_config_get_category`, `ha_config_get_label`, `ha_config_remove_category`, `ha_config_remove_label`, `ha_config_set_category`, `ha_config_set_label` |
|
|
175
175
|
| **Scenes** | `ha_config_get_scene`, `ha_config_remove_scene`, `ha_config_set_scene` |
|
|
176
176
|
| **Scripts** | `ha_config_get_script`, `ha_config_remove_script`, `ha_config_set_script` |
|
|
177
177
|
| **Search & Discovery** | `ha_deep_search`, `ha_get_overview`, `ha_get_state`, `ha_search_entities` |
|
|
178
178
|
| **Service & Device Control** | `ha_bulk_control`, `ha_call_event`, `ha_call_service`, `ha_get_operation_status`, `ha_list_services` |
|
|
179
|
-
| **System** | `ha_backup_create`, `ha_backup_restore`, `ha_check_config`, `ha_config_set_yaml` *(beta)*, `
|
|
179
|
+
| **System** | `ha_backup_create`, `ha_backup_restore`, `ha_check_config`, `ha_config_set_yaml` *(beta)*, `ha_get_updates`, `ha_manage_custom_tool` *(beta)*, `ha_reload_core`, `ha_restart` |
|
|
180
180
|
| **Todo Lists** | `ha_get_todo`, `ha_remove_todo_item`, `ha_set_todo_item` |
|
|
181
181
|
| **Utilities** | `ha_eval_template`, `ha_install_mcp_tools` *(beta)*, `ha_report_issue` |
|
|
182
182
|
| **Zones** | `ha_get_zone`, `ha_remove_zone`, `ha_set_zone` |
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ha-mcp-dev"
|
|
7
|
-
version = "7.5.0.
|
|
7
|
+
version = "7.5.0.dev542"
|
|
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"
|
|
@@ -35,7 +35,9 @@ from .util_helpers import (
|
|
|
35
35
|
build_pagination_metadata,
|
|
36
36
|
coerce_bool_param,
|
|
37
37
|
coerce_int_param,
|
|
38
|
+
fetch_integration_diagnostics,
|
|
38
39
|
get_logger_levels,
|
|
40
|
+
parse_diagnostics_fields,
|
|
39
41
|
wait_for_entity_removed,
|
|
40
42
|
)
|
|
41
43
|
|
|
@@ -219,6 +221,114 @@ class IntegrationTools:
|
|
|
219
221
|
description="Number of entries to skip for pagination (default: 0)",
|
|
220
222
|
),
|
|
221
223
|
] = 0,
|
|
224
|
+
include_diagnostics: Annotated[
|
|
225
|
+
bool | str,
|
|
226
|
+
Field(
|
|
227
|
+
description=(
|
|
228
|
+
"When entry_id is set, also fetch the integration's diagnostics "
|
|
229
|
+
"dump — integration-defined JSON (commonly includes redacted "
|
|
230
|
+
"config, device list, state snapshots; exact top-level keys "
|
|
231
|
+
"vary by integration). The canonical artifact users grab via "
|
|
232
|
+
"Settings → Devices & Services → [integration] → ⋯ → Download "
|
|
233
|
+
"diagnostics. Use when triaging integration bugs or filing "
|
|
234
|
+
"ha_report_issue for a specific integration. Payloads can be "
|
|
235
|
+
"large (Hue ~290 KB, ZHA/MQTT/ESPHome several MB) — pair with "
|
|
236
|
+
"diagnostics_fields or diagnostics_truncate_at_bytes to fit "
|
|
237
|
+
"the LLM context budget."
|
|
238
|
+
),
|
|
239
|
+
default=False,
|
|
240
|
+
),
|
|
241
|
+
] = False,
|
|
242
|
+
device_id: Annotated[
|
|
243
|
+
str | None,
|
|
244
|
+
Field(
|
|
245
|
+
description=(
|
|
246
|
+
"Optional. When set with include_diagnostics=True, returns the "
|
|
247
|
+
"device-scoped diagnostics dump for that specific device under "
|
|
248
|
+
"the integration (rather than the full integration dump). Some "
|
|
249
|
+
"integrations only expose config-entry-level dumps; others "
|
|
250
|
+
"expose both."
|
|
251
|
+
),
|
|
252
|
+
default=None,
|
|
253
|
+
),
|
|
254
|
+
] = None,
|
|
255
|
+
diagnostics_fields: Annotated[
|
|
256
|
+
list[str] | str | None,
|
|
257
|
+
Field(
|
|
258
|
+
description=(
|
|
259
|
+
"Optional list of top-level keys to keep from the diagnostics "
|
|
260
|
+
"data payload (e.g. ['home_assistant', 'issues']). Trims the "
|
|
261
|
+
"payload before it hits the LLM context budget. Accepts a JSON "
|
|
262
|
+
"list or comma-separated string. Only applies when "
|
|
263
|
+
"include_diagnostics=True and the data payload is a dict. "
|
|
264
|
+
"Unknown keys are silently dropped and surfaced via the "
|
|
265
|
+
"omitted_fields sub-key."
|
|
266
|
+
),
|
|
267
|
+
default=None,
|
|
268
|
+
),
|
|
269
|
+
] = None,
|
|
270
|
+
diagnostics_truncate_at_bytes: Annotated[
|
|
271
|
+
int | str | None,
|
|
272
|
+
Field(
|
|
273
|
+
description=(
|
|
274
|
+
"Optional byte cap on the serialized diagnostics payload "
|
|
275
|
+
"(after diagnostics_fields and diagnostics_data_path have "
|
|
276
|
+
"been applied). On hit, drops data and emits truncated=true, "
|
|
277
|
+
"bytes_total, byte_cap, plus available_fields (when the "
|
|
278
|
+
"capped value is a dict). Recommended starting point: "
|
|
279
|
+
"20000 bytes. Only applies when include_diagnostics=True."
|
|
280
|
+
),
|
|
281
|
+
default=None,
|
|
282
|
+
),
|
|
283
|
+
] = None,
|
|
284
|
+
diagnostics_data_path: Annotated[
|
|
285
|
+
str | None,
|
|
286
|
+
Field(
|
|
287
|
+
description=(
|
|
288
|
+
"Optional dotted path into the diagnostics data sub-tree "
|
|
289
|
+
"(e.g. '<list-valued path>' for per-device records, "
|
|
290
|
+
"'home_assistant.version' for HA core version; the exact "
|
|
291
|
+
"key path varies by integration version). Walks into the "
|
|
292
|
+
"post-fields payload. Resolution failures replace data "
|
|
293
|
+
"with null and surface data_path_error. Use this when the "
|
|
294
|
+
"interesting payload lives several levels deep — top-level "
|
|
295
|
+
"diagnostics_fields can't address sub-trees on integrations "
|
|
296
|
+
"where the bulk lives under one key (ZHA, MQTT, ESPHome). "
|
|
297
|
+
"Only applies when include_diagnostics=True."
|
|
298
|
+
),
|
|
299
|
+
default=None,
|
|
300
|
+
),
|
|
301
|
+
] = None,
|
|
302
|
+
diagnostics_data_offset: Annotated[
|
|
303
|
+
int | str | None,
|
|
304
|
+
Field(
|
|
305
|
+
description=(
|
|
306
|
+
"Pagination start index (default 0) for list-valued "
|
|
307
|
+
"diagnostics_data_path results. Ignored when "
|
|
308
|
+
"diagnostics_data_path is unset, diagnostics_data_limit is "
|
|
309
|
+
"unset, or the resolved value is not a list. Only applies "
|
|
310
|
+
"when include_diagnostics=True."
|
|
311
|
+
),
|
|
312
|
+
default=0,
|
|
313
|
+
),
|
|
314
|
+
] = 0,
|
|
315
|
+
diagnostics_data_limit: Annotated[
|
|
316
|
+
int | str | None,
|
|
317
|
+
Field(
|
|
318
|
+
description=(
|
|
319
|
+
"Pagination window size for list-valued "
|
|
320
|
+
"diagnostics_data_path results. When set with a "
|
|
321
|
+
"list-resolved path, swaps data for a pagination envelope "
|
|
322
|
+
"{path, items, offset, limit, total, has_more}. Default "
|
|
323
|
+
"None returns the full resolved value. Workflow: probe "
|
|
324
|
+
"with a list-valued diagnostics_data_path and "
|
|
325
|
+
"diagnostics_data_limit=10 to walk a large list one page "
|
|
326
|
+
"at a time (the exact path varies by integration version). "
|
|
327
|
+
"Only applies when include_diagnostics=True."
|
|
328
|
+
),
|
|
329
|
+
default=None,
|
|
330
|
+
),
|
|
331
|
+
] = None,
|
|
222
332
|
) -> dict[str, Any]:
|
|
223
333
|
"""Get integration (config entry) information with pagination.
|
|
224
334
|
|
|
@@ -231,6 +341,10 @@ class IntegrationTools:
|
|
|
231
341
|
- Search: ha_get_integration(query="zigbee")
|
|
232
342
|
- Get specific entry: ha_get_integration(entry_id="abc123")
|
|
233
343
|
- Get entry with editable fields: ha_get_integration(entry_id="abc123", include_schema=True)
|
|
344
|
+
- Get entry with diagnostics dump: ha_get_integration(entry_id="abc123", include_diagnostics=True)
|
|
345
|
+
- Get device-scoped diagnostics: ha_get_integration(entry_id="abc123", include_diagnostics=True, device_id="dev123")
|
|
346
|
+
- Walk a sub-tree: ha_get_integration(entry_id="abc123", include_diagnostics=True, diagnostics_data_path="<dotted-path>")
|
|
347
|
+
- Paginate a large list: ha_get_integration(entry_id="abc123", include_diagnostics=True, diagnostics_data_path="<list-valued path>", diagnostics_data_limit=10, diagnostics_data_offset=20)
|
|
234
348
|
- List template entries: ha_get_integration(domain="template")
|
|
235
349
|
|
|
236
350
|
STATES: 'loaded', 'setup_error', 'setup_retry', 'not_loaded',
|
|
@@ -256,6 +370,9 @@ class IntegrationTools:
|
|
|
256
370
|
include_schema_bool = coerce_bool_param(
|
|
257
371
|
include_schema, "include_schema", default=False
|
|
258
372
|
)
|
|
373
|
+
include_diagnostics_bool = coerce_bool_param(
|
|
374
|
+
include_diagnostics, "include_diagnostics", default=False
|
|
375
|
+
)
|
|
259
376
|
exact_match_bool = coerce_bool_param(
|
|
260
377
|
exact_match, "exact_match", default=True
|
|
261
378
|
)
|
|
@@ -263,18 +380,86 @@ class IntegrationTools:
|
|
|
263
380
|
limit, "limit", default=50, min_value=1, max_value=200
|
|
264
381
|
)
|
|
265
382
|
offset_int = coerce_int_param(offset, "offset", default=0, min_value=0)
|
|
383
|
+
fields_list = parse_diagnostics_fields(diagnostics_fields)
|
|
384
|
+
truncate_bytes = coerce_int_param(
|
|
385
|
+
diagnostics_truncate_at_bytes,
|
|
386
|
+
"diagnostics_truncate_at_bytes",
|
|
387
|
+
default=None,
|
|
388
|
+
min_value=1,
|
|
389
|
+
)
|
|
390
|
+
data_offset_int = coerce_int_param(
|
|
391
|
+
diagnostics_data_offset,
|
|
392
|
+
"diagnostics_data_offset",
|
|
393
|
+
default=0,
|
|
394
|
+
min_value=0,
|
|
395
|
+
)
|
|
396
|
+
data_limit_int = coerce_int_param(
|
|
397
|
+
diagnostics_data_limit,
|
|
398
|
+
"diagnostics_data_limit",
|
|
399
|
+
default=None,
|
|
400
|
+
min_value=1,
|
|
401
|
+
)
|
|
402
|
+
# Type-guard ``diagnostics_data_path`` here so a bad caller (dict /
|
|
403
|
+
# list) surfaces as ``VALIDATION_INVALID_PARAMETER`` instead of
|
|
404
|
+
# leaking as ``INTERNAL_ERROR`` from the resolver's ``.strip()``
|
|
405
|
+
# downstream. Mirrors the coerce_int_param guards above.
|
|
406
|
+
if diagnostics_data_path is not None and not isinstance(
|
|
407
|
+
diagnostics_data_path, str
|
|
408
|
+
):
|
|
409
|
+
raise_tool_error(
|
|
410
|
+
create_error_response(
|
|
411
|
+
ErrorCode.VALIDATION_INVALID_PARAMETER,
|
|
412
|
+
"diagnostics_data_path must be a string, got "
|
|
413
|
+
f"{type(diagnostics_data_path).__name__}",
|
|
414
|
+
context={"parameter": "diagnostics_data_path"},
|
|
415
|
+
)
|
|
416
|
+
)
|
|
266
417
|
# Auto-enable options when domain filter is set
|
|
267
418
|
if domain is not None:
|
|
268
419
|
include_opts = True
|
|
269
420
|
|
|
270
421
|
# If entry_id provided, get specific config entry
|
|
271
422
|
if entry_id is not None:
|
|
272
|
-
|
|
423
|
+
resp = await self._get_single_entry(entry_id, include_schema_bool)
|
|
424
|
+
if include_diagnostics_bool:
|
|
425
|
+
resp["diagnostics"] = await fetch_integration_diagnostics(
|
|
426
|
+
self._client,
|
|
427
|
+
entry_id,
|
|
428
|
+
device_id,
|
|
429
|
+
fields=fields_list,
|
|
430
|
+
truncate_at_bytes=truncate_bytes,
|
|
431
|
+
data_path=diagnostics_data_path,
|
|
432
|
+
data_offset=data_offset_int,
|
|
433
|
+
data_limit=data_limit_int,
|
|
434
|
+
)
|
|
435
|
+
elif device_id is not None:
|
|
436
|
+
resp.setdefault("warnings", []).append(
|
|
437
|
+
"device_id was provided but ignored because "
|
|
438
|
+
"include_diagnostics=False"
|
|
439
|
+
)
|
|
440
|
+
return resp
|
|
273
441
|
|
|
274
442
|
# List mode - get all config entries
|
|
275
|
-
|
|
443
|
+
result = await self._list_entries(
|
|
276
444
|
domain, query, include_opts, exact_match_bool, limit_int, offset_int
|
|
277
445
|
)
|
|
446
|
+
if (
|
|
447
|
+
include_diagnostics_bool
|
|
448
|
+
or device_id is not None
|
|
449
|
+
or fields_list is not None
|
|
450
|
+
or truncate_bytes is not None
|
|
451
|
+
or diagnostics_data_path is not None
|
|
452
|
+
or data_limit_int is not None
|
|
453
|
+
or data_offset_int > 0
|
|
454
|
+
):
|
|
455
|
+
result.setdefault("warnings", []).append(
|
|
456
|
+
"include_diagnostics, device_id, diagnostics_fields, "
|
|
457
|
+
"diagnostics_truncate_at_bytes, diagnostics_data_path, "
|
|
458
|
+
"diagnostics_data_offset, and/or diagnostics_data_limit "
|
|
459
|
+
"were provided but ignored because entry_id was not set "
|
|
460
|
+
"(list mode)"
|
|
461
|
+
)
|
|
462
|
+
return result
|
|
278
463
|
|
|
279
464
|
except ToolError:
|
|
280
465
|
raise
|
|
@@ -23,7 +23,13 @@ from .helpers import (
|
|
|
23
23
|
raise_tool_error,
|
|
24
24
|
register_tool_methods,
|
|
25
25
|
)
|
|
26
|
-
from .util_helpers import
|
|
26
|
+
from .util_helpers import (
|
|
27
|
+
coerce_bool_param,
|
|
28
|
+
coerce_int_param,
|
|
29
|
+
fetch_integration_diagnostics,
|
|
30
|
+
filter_active_repairs,
|
|
31
|
+
parse_diagnostics_fields,
|
|
32
|
+
)
|
|
27
33
|
|
|
28
34
|
logger = logging.getLogger(__name__)
|
|
29
35
|
|
|
@@ -334,17 +340,24 @@ class SystemTools:
|
|
|
334
340
|
|
|
335
341
|
@tool(
|
|
336
342
|
name="ha_get_system_health",
|
|
337
|
-
tags={"System", "Zigbee", "Z-Wave"},
|
|
338
|
-
annotations={"idempotentHint": True, "readOnlyHint": True, "title": "Get System Health (incl. ZHA/Z-Wave diagnostics)"},
|
|
343
|
+
tags={"System", "Zigbee", "Z-Wave", "Integrations"},
|
|
344
|
+
annotations={"idempotentHint": True, "readOnlyHint": True, "title": "Get System Health (incl. ZHA/Z-Wave/integration diagnostics)"},
|
|
339
345
|
)
|
|
340
346
|
@log_tool_usage
|
|
341
347
|
async def ha_get_system_health(
|
|
342
348
|
self,
|
|
343
349
|
include: str | None = None,
|
|
344
350
|
include_dismissed_repairs: bool | str | None = False,
|
|
351
|
+
config_entry_id: str | None = None,
|
|
352
|
+
device_id: str | None = None,
|
|
353
|
+
diagnostics_fields: list[str] | str | None = None,
|
|
354
|
+
diagnostics_truncate_at_bytes: int | str | None = None,
|
|
355
|
+
diagnostics_data_path: str | None = None,
|
|
356
|
+
diagnostics_data_offset: int | str | None = 0,
|
|
357
|
+
diagnostics_data_limit: int | str | None = None,
|
|
345
358
|
) -> dict[str, Any]:
|
|
346
359
|
"""
|
|
347
|
-
Get Home Assistant system health, including Zigbee (ZHA)
|
|
360
|
+
Get Home Assistant system health, including Zigbee (ZHA), Z-Wave JS, and per-integration diagnostics dumps.
|
|
348
361
|
|
|
349
362
|
Returns health check results from integrations, system resources, and connectivity.
|
|
350
363
|
Available information varies by installation type and loaded integrations.
|
|
@@ -355,8 +368,50 @@ class SystemTools:
|
|
|
355
368
|
- "zha_network": ZHA Zigbee devices with radio signal summary (name, LQI, RSSI)
|
|
356
369
|
- "zha_network_full": ZHA Zigbee devices with all device details (can be large on 100+ device networks; prefer "zha_network" for summary)
|
|
357
370
|
- "zwave_network": Z-Wave JS network status and node summary (status, security, routing)
|
|
371
|
+
- "diagnostics": Per-integration diagnostics dump — integration-defined JSON
|
|
372
|
+
(commonly includes redacted config, device list, state snapshots; exact
|
|
373
|
+
top-level keys vary by integration). REQUIRES ``config_entry_id``. The
|
|
374
|
+
canonical artifact users grab via Settings → Devices & Services →
|
|
375
|
+
[integration] → ⋯ → Download diagnostics. Use this when triaging integration
|
|
376
|
+
bugs or filing ``ha_report_issue`` for a specific integration. Payloads can
|
|
377
|
+
be large (Hue ~290 KB, ZHA/MQTT/ESPHome several MB) — pair with
|
|
378
|
+
``diagnostics_fields`` or ``diagnostics_truncate_at_bytes`` to fit the LLM
|
|
379
|
+
context budget.
|
|
358
380
|
- Example: include="repairs,zha_network,zwave_network"
|
|
381
|
+
- Example: include="diagnostics", config_entry_id="abc123..."
|
|
359
382
|
- include_dismissed_repairs: Include user-dismissed/ignored repairs (default: False). Only meaningful when "repairs" is in `include`.
|
|
383
|
+
- config_entry_id: Required when ``include`` contains ``diagnostics``. The config
|
|
384
|
+
entry ID of the integration (find via ``ha_get_integration``).
|
|
385
|
+
- device_id: Optional. When set with ``include=diagnostics``, returns the
|
|
386
|
+
device-scoped diagnostics dump for that specific device under the integration
|
|
387
|
+
(rather than the full integration dump). Some integrations only expose
|
|
388
|
+
config-entry-level dumps; others expose both.
|
|
389
|
+
- diagnostics_fields: Optional list of top-level keys to keep from the
|
|
390
|
+
diagnostics ``data`` payload (e.g. ``["home_assistant", "issues"]``). Accepts
|
|
391
|
+
a JSON list or comma-separated string. Only applies with ``include=diagnostics``.
|
|
392
|
+
- diagnostics_truncate_at_bytes: Optional byte cap on the serialized
|
|
393
|
+
diagnostics payload (post-projection / post-data_path). On hit,
|
|
394
|
+
drops ``data`` and emits ``truncated=true``, ``bytes_total``,
|
|
395
|
+
``byte_cap``, plus ``available_fields`` (when the capped value
|
|
396
|
+
is a dict). Only applies when ``include`` contains ``diagnostics``.
|
|
397
|
+
Recommended starting point: 20000 bytes.
|
|
398
|
+
- diagnostics_data_path: Optional dotted path into the diagnostics
|
|
399
|
+
``data`` sub-tree (e.g. ``"data.devices"`` for ZHA per-device records).
|
|
400
|
+
Walks into the post-fields payload. Resolution failures replace
|
|
401
|
+
``data`` with ``null`` and surface ``data_path_error``. Only applies
|
|
402
|
+
when ``include`` contains ``diagnostics``.
|
|
403
|
+
- diagnostics_data_offset / diagnostics_data_limit: Pagination on
|
|
404
|
+
list-valued ``diagnostics_data_path`` results. When ``data_limit``
|
|
405
|
+
is set and the resolved path is a list, ``data`` becomes
|
|
406
|
+
``{"path", "items", "offset", "limit", "total", "has_more"}``. Only
|
|
407
|
+
applies when ``include`` contains ``diagnostics``.
|
|
408
|
+
|
|
409
|
+
Example workflow (walk a list-valued sub-tree one page at a time;
|
|
410
|
+
the exact ``data_path`` varies by integration version):
|
|
411
|
+
``ha_get_system_health(include="diagnostics", config_entry_id="abc",
|
|
412
|
+
diagnostics_data_path="<list-valued path>", diagnostics_data_limit=10)``
|
|
413
|
+
→ inspect the page envelope's ``total`` / ``has_more`` → repeat
|
|
414
|
+
with ``diagnostics_data_offset=10`` for the next slice.
|
|
360
415
|
"""
|
|
361
416
|
includes = self._parse_includes(include)
|
|
362
417
|
include_dismissed_repairs_bool = bool(
|
|
@@ -373,10 +428,18 @@ class SystemTools:
|
|
|
373
428
|
ws_client, result = await self._fetch_health_info()
|
|
374
429
|
|
|
375
430
|
# Warn about unrecognized include values
|
|
376
|
-
VALID_INCLUDES = {
|
|
431
|
+
VALID_INCLUDES = {
|
|
432
|
+
"repairs",
|
|
433
|
+
"zha_network",
|
|
434
|
+
"zha_network_full",
|
|
435
|
+
"zwave_network",
|
|
436
|
+
"diagnostics",
|
|
437
|
+
}
|
|
377
438
|
unknown = includes - VALID_INCLUDES
|
|
378
439
|
if unknown:
|
|
379
|
-
result
|
|
440
|
+
result.setdefault("warnings", []).append(
|
|
441
|
+
f"Unknown include sections ignored: {', '.join(sorted(unknown))}"
|
|
442
|
+
)
|
|
380
443
|
|
|
381
444
|
# Fetch optional sections concurrently. The ws_client serialises
|
|
382
445
|
# outgoing writes via its internal `_send_lock`, but per-message
|
|
@@ -462,6 +525,81 @@ class SystemTools:
|
|
|
462
525
|
else:
|
|
463
526
|
result[section_name] = section_result
|
|
464
527
|
|
|
528
|
+
# Diagnostics-related coercions live outside the includes branch
|
|
529
|
+
# so the orphan-args warning at the ``elif`` after the
|
|
530
|
+
# ``if "diagnostics" in includes`` block (see below) can see
|
|
531
|
+
# canonicalised values — passing ``diagnostics_data_offset=20``
|
|
532
|
+
# without ``include=diagnostics`` would otherwise slip past the gate.
|
|
533
|
+
fields_list = parse_diagnostics_fields(diagnostics_fields)
|
|
534
|
+
truncate_bytes = coerce_int_param(
|
|
535
|
+
diagnostics_truncate_at_bytes,
|
|
536
|
+
"diagnostics_truncate_at_bytes",
|
|
537
|
+
default=None,
|
|
538
|
+
min_value=1,
|
|
539
|
+
)
|
|
540
|
+
data_offset_int = coerce_int_param(
|
|
541
|
+
diagnostics_data_offset,
|
|
542
|
+
"diagnostics_data_offset",
|
|
543
|
+
default=0,
|
|
544
|
+
min_value=0,
|
|
545
|
+
)
|
|
546
|
+
data_limit_int = coerce_int_param(
|
|
547
|
+
diagnostics_data_limit,
|
|
548
|
+
"diagnostics_data_limit",
|
|
549
|
+
default=None,
|
|
550
|
+
min_value=1,
|
|
551
|
+
)
|
|
552
|
+
# Type-guard ``diagnostics_data_path`` here so a bad caller (dict /
|
|
553
|
+
# list) surfaces as ``VALIDATION_INVALID_PARAMETER`` instead of
|
|
554
|
+
# leaking as ``INTERNAL_ERROR`` from the resolver's ``.strip()``
|
|
555
|
+
# downstream. Mirrors the coerce_int_param guards above.
|
|
556
|
+
if diagnostics_data_path is not None and not isinstance(
|
|
557
|
+
diagnostics_data_path, str
|
|
558
|
+
):
|
|
559
|
+
raise_tool_error(
|
|
560
|
+
create_error_response(
|
|
561
|
+
ErrorCode.VALIDATION_INVALID_PARAMETER,
|
|
562
|
+
"diagnostics_data_path must be a string, got "
|
|
563
|
+
f"{type(diagnostics_data_path).__name__}",
|
|
564
|
+
context={"parameter": "diagnostics_data_path"},
|
|
565
|
+
)
|
|
566
|
+
)
|
|
567
|
+
|
|
568
|
+
if "diagnostics" in includes:
|
|
569
|
+
# ``fetch_integration_diagnostics`` carries the empty-id guard
|
|
570
|
+
# (returns {"config_entry_id": ..., "error": ...}); calling it
|
|
571
|
+
# unconditionally keeps the missing-id error shape consistent
|
|
572
|
+
# with the populated path instead of returning a bare
|
|
573
|
+
# ``{"error": ...}`` sub-dict on the inline branch. Forward
|
|
574
|
+
# ``config_entry_id`` as-is (None / "") so the helper's echo
|
|
575
|
+
# field reflects what the caller actually passed.
|
|
576
|
+
result["diagnostics"] = await fetch_integration_diagnostics(
|
|
577
|
+
self._client,
|
|
578
|
+
config_entry_id,
|
|
579
|
+
device_id,
|
|
580
|
+
fields=fields_list,
|
|
581
|
+
truncate_at_bytes=truncate_bytes,
|
|
582
|
+
data_path=diagnostics_data_path,
|
|
583
|
+
data_offset=data_offset_int,
|
|
584
|
+
data_limit=data_limit_int,
|
|
585
|
+
)
|
|
586
|
+
elif (
|
|
587
|
+
config_entry_id
|
|
588
|
+
or device_id
|
|
589
|
+
or diagnostics_fields is not None
|
|
590
|
+
or diagnostics_truncate_at_bytes is not None
|
|
591
|
+
or diagnostics_data_path is not None
|
|
592
|
+
or diagnostics_data_limit is not None
|
|
593
|
+
or data_offset_int > 0
|
|
594
|
+
):
|
|
595
|
+
result.setdefault("warnings", []).append(
|
|
596
|
+
"config_entry_id, device_id, diagnostics_fields, "
|
|
597
|
+
"diagnostics_truncate_at_bytes, diagnostics_data_path, "
|
|
598
|
+
"diagnostics_data_offset, and/or diagnostics_data_limit "
|
|
599
|
+
"were provided but ignored because 'diagnostics' is not "
|
|
600
|
+
"in include"
|
|
601
|
+
)
|
|
602
|
+
|
|
465
603
|
return result
|
|
466
604
|
|
|
467
605
|
except ToolError:
|