ha-mcp-dev 7.12.3.dev1879__tar.gz → 7.12.3.dev1882__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.12.3.dev1879/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.12.3.dev1882}/PKG-INFO +1 -1
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/pyproject.toml +1 -1
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/policy/value_sources.py +17 -1
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/config_entry_flow.py +177 -38
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_integrations.py +202 -48
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/LICENSE +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/MANIFEST.in +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/README.md +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/setup.cfg +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/__main__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/_pypi_marker +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/_version.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/auth/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/auth/consent_form.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/auth/provider.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/backup_manager.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/browser_landing.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/client/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/client/rest_client.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/client/supervisor_client.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/client/websocket_client.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/client/websocket_listener.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/config.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/errors.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/llm_exposure.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/policy/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/policy/approval_queue.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/policy/evaluator.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/policy/handlers.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/policy/middleware.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/policy/model.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/policy/persistence.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/py.typed +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/read_only.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/appdaemon.md +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/blueprint-guide.md +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/scenes.md +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/server.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/settings_ui/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/settings_ui/settings.css +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/settings_ui/settings.html +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/settings_ui/settings.js +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/smoke_test.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/auto_backup.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/backup.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/best_practice_checker.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/component_api.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/device_control.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/enhanced.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/helpers.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/radio/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/radio/base.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/radio/matter.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/radio/thread.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/radio/zigbee.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/radio/zwave.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/reference_validator.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/registry.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/smart_search/_base.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/smart_search/_config.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tool_search_hint_middleware.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_addons.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_areas.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_blueprints.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_bug_report.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_calendar.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_camera.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_categories.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_code.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_config_automations.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_dev.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_energy.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_entities.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_filesystem.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_groups.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_hacs.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_history.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_labels.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_radio.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_registry.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_resources.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_search.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_service.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_services.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_system.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_themes.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_todo.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_traces.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_updates.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_utility.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/tools_zones.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/util_helpers.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/validation_middleware.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/transforms/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/transforms/categorized_search.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/transport_security.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/update_check.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/utils/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/utils/config_hash.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/utils/data_paths.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/utils/domain_handlers.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/utils/fuzzy_search.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/utils/operation_manager.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/utils/python_sandbox.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/utils/skill_loader.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/utils/usage_logger.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/visibility/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/visibility/model.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/visibility/persistence.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/visibility/resolver.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/tests/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/tests/test_constants.py +0 -0
- {ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/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.12.3.
|
|
7
|
+
version = "7.12.3.dev1882"
|
|
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
|
|
@@ -40,7 +40,7 @@ VALUE_SOURCE_REGISTRY: dict[tuple[str, str], str] = {
|
|
|
40
40
|
("ha_get_history", "args.entity_ids"): "ha_entities",
|
|
41
41
|
("ha_remove_entity", "args.entity_id"): "ha_entities",
|
|
42
42
|
("ha_get_entity_exposure", "args.entity_id"): "ha_entities",
|
|
43
|
-
("
|
|
43
|
+
("ha_set_integration", "args.entry_id"): "ha_config_entries",
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
# Fetched-value TTL cache so the UI can click through path options
|
|
@@ -171,8 +171,24 @@ async def _fetch_ha_entities(client: Any, params: dict[str, str]) -> list[str]:
|
|
|
171
171
|
return out
|
|
172
172
|
|
|
173
173
|
|
|
174
|
+
async def _fetch_ha_config_entries(client: Any, _params: dict[str, str]) -> list[str]:
|
|
175
|
+
entries = await client._request("GET", "/config/config_entries/entry")
|
|
176
|
+
if not isinstance(entries, list):
|
|
177
|
+
logger.warning(
|
|
178
|
+
"ha_config_entries: config entry list returned unexpected shape %s",
|
|
179
|
+
type(entries).__name__,
|
|
180
|
+
)
|
|
181
|
+
return []
|
|
182
|
+
return [
|
|
183
|
+
e["entry_id"]
|
|
184
|
+
for e in entries
|
|
185
|
+
if isinstance(e, dict) and isinstance(e.get("entry_id"), str)
|
|
186
|
+
]
|
|
187
|
+
|
|
188
|
+
|
|
174
189
|
_FETCHERS: dict[str, Callable[[Any, dict[str, str]], Awaitable[list[str]]]] = {
|
|
175
190
|
"ha_domains": _fetch_ha_domains,
|
|
176
191
|
"ha_services": _fetch_ha_services,
|
|
177
192
|
"ha_entities": _fetch_ha_entities,
|
|
193
|
+
"ha_config_entries": _fetch_ha_config_entries,
|
|
178
194
|
}
|
{ha_mcp_dev-7.12.3.dev1879 → ha_mcp_dev-7.12.3.dev1882}/src/ha_mcp/tools/config_entry_flow.py
RENAMED
|
@@ -14,7 +14,7 @@ import asyncio
|
|
|
14
14
|
import logging
|
|
15
15
|
from collections.abc import Iterator
|
|
16
16
|
from enum import StrEnum
|
|
17
|
-
from typing import Any, Literal
|
|
17
|
+
from typing import Any, Literal, NoReturn
|
|
18
18
|
|
|
19
19
|
from ..client.rest_client import HomeAssistantAPIError
|
|
20
20
|
from ..errors import ErrorCode, create_error_response
|
|
@@ -65,6 +65,13 @@ FLOW_HELPER_TYPES: frozenset[str] = frozenset(
|
|
|
65
65
|
|
|
66
66
|
# Keys used to specify a menu selection — stripped before submitting form data.
|
|
67
67
|
_MENU_SELECTION_KEYS = frozenset({"group_type", "next_step_id", "menu_option"})
|
|
68
|
+
|
|
69
|
+
# Flow step types an MCP client cannot drive: external steps need a browser
|
|
70
|
+
# (OAuth / cloud authorization), progress steps wait on HA-side async work.
|
|
71
|
+
# Surfaced as structured errors instead of attempted (issue #1814).
|
|
72
|
+
_UNDRIVABLE_STEP_TYPES = frozenset(
|
|
73
|
+
{"external", "external_done", "progress", "progress_done"}
|
|
74
|
+
)
|
|
68
75
|
_RECONFIGURE_SUCCESS_REASONS = frozenset(
|
|
69
76
|
{
|
|
70
77
|
"reauth_successful",
|
|
@@ -618,6 +625,74 @@ async def _submit_step(
|
|
|
618
625
|
raise
|
|
619
626
|
|
|
620
627
|
|
|
628
|
+
def _finish_flow_entry(
|
|
629
|
+
flow_id: str,
|
|
630
|
+
current_step: dict[str, Any],
|
|
631
|
+
*,
|
|
632
|
+
supplied_keys: list[str],
|
|
633
|
+
saw_form_step: bool,
|
|
634
|
+
any_form_key_consumed: bool,
|
|
635
|
+
ignored_config_keys: set[str],
|
|
636
|
+
remaining_config: dict[str, Any],
|
|
637
|
+
) -> dict[str, Any]:
|
|
638
|
+
"""Build the CREATE_ENTRY success response, or raise on total key miss.
|
|
639
|
+
|
|
640
|
+
When the flow presented at least one form step, the caller supplied
|
|
641
|
+
config keys, and NONE were consumed by any form (typos / wrong field
|
|
642
|
+
names), the flow was walked on empty forms and HA saved form defaults —
|
|
643
|
+
not the caller's values. A success + warning there reads as "done" to an
|
|
644
|
+
LLM caller, so fail loudly with the schema route instead. Partial
|
|
645
|
+
consumption — and flows that complete without any form step (instant
|
|
646
|
+
creates) — keep the established success + warnings contract.
|
|
647
|
+
"""
|
|
648
|
+
if supplied_keys and saw_form_step and not any_form_key_consumed:
|
|
649
|
+
raise_tool_error(
|
|
650
|
+
create_error_response(
|
|
651
|
+
ErrorCode.VALIDATION_INVALID_PARAMETER,
|
|
652
|
+
"Flow completed without consuming any of the supplied "
|
|
653
|
+
"config keys — every form step was submitted empty, so "
|
|
654
|
+
"the flow saved its defaults, not your values",
|
|
655
|
+
suggestions=[
|
|
656
|
+
"Check the field names against the flow's data_schema — "
|
|
657
|
+
"ha_get_integration(entry_id=..., include_schema=True) "
|
|
658
|
+
"shows the accepted fields — then retry with corrected "
|
|
659
|
+
"keys.",
|
|
660
|
+
],
|
|
661
|
+
context={
|
|
662
|
+
"flow_id": flow_id,
|
|
663
|
+
"supplied_keys": supplied_keys,
|
|
664
|
+
"details": current_step,
|
|
665
|
+
},
|
|
666
|
+
)
|
|
667
|
+
)
|
|
668
|
+
response: dict[str, Any] = {"success": True, "entry": current_step}
|
|
669
|
+
warnings = _ignored_keys_warnings(ignored_config_keys, remaining_config)
|
|
670
|
+
if warnings:
|
|
671
|
+
response["warnings"] = warnings
|
|
672
|
+
return response
|
|
673
|
+
|
|
674
|
+
|
|
675
|
+
def _raise_flow_abort(flow_id: str, current_step: dict[str, Any]) -> NoReturn:
|
|
676
|
+
"""Raise the structured error for an ABORT flow step."""
|
|
677
|
+
reason = current_step.get("reason")
|
|
678
|
+
abort_suggestions: list[str] = []
|
|
679
|
+
if reason in ("already_configured", "single_instance_allowed"):
|
|
680
|
+
# Common benign aborts on the add-integration path (#1814): give the
|
|
681
|
+
# caller a route to the existing entry instead of a bare failure.
|
|
682
|
+
abort_suggestions.append(
|
|
683
|
+
"The integration is already set up — use "
|
|
684
|
+
"ha_get_integration() to find the existing entry."
|
|
685
|
+
)
|
|
686
|
+
raise_tool_error(
|
|
687
|
+
create_error_response(
|
|
688
|
+
ErrorCode.SERVICE_CALL_FAILED,
|
|
689
|
+
f"Flow aborted: {reason}",
|
|
690
|
+
suggestions=abort_suggestions or None,
|
|
691
|
+
context={"flow_id": flow_id, "details": current_step},
|
|
692
|
+
)
|
|
693
|
+
)
|
|
694
|
+
|
|
695
|
+
|
|
621
696
|
async def _handle_flow_steps(
|
|
622
697
|
client: Any,
|
|
623
698
|
flow_id: str,
|
|
@@ -650,8 +725,12 @@ async def _handle_flow_steps(
|
|
|
650
725
|
|
|
651
726
|
Returns:
|
|
652
727
|
``{"success": True, "entry": result}`` on success, plus ``warnings``
|
|
653
|
-
when caller-supplied config keys were not declared by any flow
|
|
654
|
-
|
|
728
|
+
when SOME caller-supplied config keys were not declared by any flow
|
|
729
|
+
step. When the flow presented at least one form step and NONE of the
|
|
730
|
+
supplied keys were consumed, raises ``VALIDATION_INVALID_PARAMETER``
|
|
731
|
+
instead of reporting a misleading success — the flow completed on
|
|
732
|
+
empty forms (defaults), applying nothing the caller asked for (see
|
|
733
|
+
:func:`_finish_flow_entry`). Raises ToolError on any failure.
|
|
655
734
|
"""
|
|
656
735
|
if submit_fn is None:
|
|
657
736
|
submit_fn = client.submit_config_flow_step
|
|
@@ -659,26 +738,27 @@ async def _handle_flow_steps(
|
|
|
659
738
|
current_step = initial_step
|
|
660
739
|
last_menu_choice: str | None = None
|
|
661
740
|
ignored_config_keys: set[str] = set()
|
|
741
|
+
supplied_keys = sorted(k for k in config if k not in _MENU_SELECTION_KEYS)
|
|
742
|
+
saw_form_step = False
|
|
743
|
+
any_form_key_consumed = False
|
|
662
744
|
max_steps = 10
|
|
663
745
|
|
|
664
746
|
for step_num in range(max_steps):
|
|
665
747
|
result_type = current_step.get("type")
|
|
666
748
|
|
|
667
749
|
if result_type == _FlowType.CREATE_ENTRY:
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
750
|
+
return _finish_flow_entry(
|
|
751
|
+
flow_id,
|
|
752
|
+
current_step,
|
|
753
|
+
supplied_keys=supplied_keys,
|
|
754
|
+
saw_form_step=saw_form_step,
|
|
755
|
+
any_form_key_consumed=any_form_key_consumed,
|
|
756
|
+
ignored_config_keys=ignored_config_keys,
|
|
757
|
+
remaining_config=remaining_config,
|
|
758
|
+
)
|
|
673
759
|
|
|
674
760
|
if result_type == _FlowType.ABORT:
|
|
675
|
-
|
|
676
|
-
create_error_response(
|
|
677
|
-
ErrorCode.SERVICE_CALL_FAILED,
|
|
678
|
-
f"Flow aborted: {current_step.get('reason')}",
|
|
679
|
-
context={"flow_id": flow_id, "details": current_step},
|
|
680
|
-
)
|
|
681
|
-
)
|
|
761
|
+
_raise_flow_abort(flow_id, current_step)
|
|
682
762
|
|
|
683
763
|
if result_type == _FlowType.MENU:
|
|
684
764
|
menu_choice = _handle_menu_step(flow_id, current_step, remaining_config)
|
|
@@ -702,12 +782,15 @@ async def _handle_flow_steps(
|
|
|
702
782
|
# step's data_schema, leaving any other keys in remaining_config
|
|
703
783
|
# for subsequent steps (HA can present multi-step forms, e.g.
|
|
704
784
|
# statistics: user step then pick-characteristic step).
|
|
785
|
+
saw_form_step = True
|
|
705
786
|
form_data = _handle_form_step(
|
|
706
787
|
flow_id,
|
|
707
788
|
current_step,
|
|
708
789
|
remaining_config,
|
|
709
790
|
ignored_config_keys,
|
|
710
791
|
)
|
|
792
|
+
if form_data:
|
|
793
|
+
any_form_key_consumed = True
|
|
711
794
|
logger.debug(
|
|
712
795
|
f"Flow step {step_num}: form submit "
|
|
713
796
|
f"(step_id={current_step.get('step_id')}, keys={list(form_data.keys())})"
|
|
@@ -722,6 +805,21 @@ async def _handle_flow_steps(
|
|
|
722
805
|
current_step=current_step,
|
|
723
806
|
)
|
|
724
807
|
|
|
808
|
+
elif result_type in _UNDRIVABLE_STEP_TYPES:
|
|
809
|
+
raise_tool_error(
|
|
810
|
+
create_error_response(
|
|
811
|
+
ErrorCode.SERVICE_CALL_FAILED,
|
|
812
|
+
f"Flow reached a '{result_type}' step that cannot be "
|
|
813
|
+
"completed via MCP (browser/OAuth authorization or an "
|
|
814
|
+
"asynchronous provider step)",
|
|
815
|
+
suggestions=[
|
|
816
|
+
"Complete this flow in the Home Assistant UI "
|
|
817
|
+
"(Settings > Devices & Services)."
|
|
818
|
+
],
|
|
819
|
+
context={"flow_id": flow_id, "details": current_step},
|
|
820
|
+
)
|
|
821
|
+
)
|
|
822
|
+
|
|
725
823
|
else:
|
|
726
824
|
raise_tool_error(
|
|
727
825
|
create_error_response(
|
|
@@ -981,30 +1079,35 @@ async def get_user_step_field_names(client: Any, helper_type: str) -> set[str] |
|
|
|
981
1079
|
)
|
|
982
1080
|
|
|
983
1081
|
|
|
984
|
-
async def
|
|
1082
|
+
async def update_config_entry_options(
|
|
985
1083
|
client: Any,
|
|
986
|
-
helper_type: str,
|
|
987
|
-
config_dict: dict[str, Any],
|
|
988
1084
|
entry_id: str,
|
|
1085
|
+
config_dict: dict[str, Any],
|
|
1086
|
+
*,
|
|
1087
|
+
expected_domain: str | None = None,
|
|
1088
|
+
noun: str = "integration",
|
|
989
1089
|
) -> dict[str, Any]:
|
|
990
|
-
"""Update an existing
|
|
1090
|
+
"""Update an existing config entry via its options flow.
|
|
991
1091
|
|
|
992
|
-
|
|
993
|
-
|
|
1092
|
+
When ``expected_domain`` is provided, verifies the entry's domain matches
|
|
1093
|
+
it first (the helper path passes the helper_type; the generic
|
|
1094
|
+
``ha_set_integration`` path passes ``None`` to accept any domain). Starts
|
|
1095
|
+
an options flow, walks the flow steps, and returns the result. Aborts the
|
|
1096
|
+
flow on error. ``noun`` only affects response wording.
|
|
994
1097
|
"""
|
|
995
1098
|
config_entry = await client.get_config_entry(entry_id)
|
|
996
1099
|
actual_domain = config_entry.get("domain")
|
|
997
|
-
if actual_domain !=
|
|
1100
|
+
if expected_domain is not None and actual_domain != expected_domain:
|
|
998
1101
|
raise_tool_error(
|
|
999
1102
|
create_error_response(
|
|
1000
1103
|
ErrorCode.VALIDATION_INVALID_PARAMETER,
|
|
1001
|
-
f"entry_id '{entry_id}' belongs to domain '{actual_domain}', not '{
|
|
1104
|
+
f"entry_id '{entry_id}' belongs to domain '{actual_domain}', not '{expected_domain}'",
|
|
1002
1105
|
suggestions=[
|
|
1003
|
-
f"Use ha_get_integration(domain='{
|
|
1106
|
+
f"Use ha_get_integration(domain='{expected_domain}') to find valid entry IDs",
|
|
1004
1107
|
],
|
|
1005
1108
|
context={
|
|
1006
1109
|
"entry_id": entry_id,
|
|
1007
|
-
"expected":
|
|
1110
|
+
"expected": expected_domain,
|
|
1008
1111
|
"actual": actual_domain,
|
|
1009
1112
|
},
|
|
1010
1113
|
)
|
|
@@ -1032,7 +1135,7 @@ async def update_flow_helper(
|
|
|
1032
1135
|
flow_result,
|
|
1033
1136
|
config_dict,
|
|
1034
1137
|
submit_fn=client.submit_options_flow_step,
|
|
1035
|
-
helper_type=
|
|
1138
|
+
helper_type=expected_domain,
|
|
1036
1139
|
)
|
|
1037
1140
|
except Exception:
|
|
1038
1141
|
try:
|
|
@@ -1048,8 +1151,8 @@ async def update_flow_helper(
|
|
|
1048
1151
|
"success": True,
|
|
1049
1152
|
"entry_id": entry_id,
|
|
1050
1153
|
"title": entry.get("title"),
|
|
1051
|
-
"domain":
|
|
1052
|
-
"message": f"{
|
|
1154
|
+
"domain": actual_domain,
|
|
1155
|
+
"message": f"{actual_domain} {noun} updated successfully",
|
|
1053
1156
|
"updated": True,
|
|
1054
1157
|
}
|
|
1055
1158
|
if result.get("warnings"):
|
|
@@ -1057,17 +1160,40 @@ async def update_flow_helper(
|
|
|
1057
1160
|
return response
|
|
1058
1161
|
|
|
1059
1162
|
|
|
1060
|
-
async def
|
|
1163
|
+
async def update_flow_helper(
|
|
1061
1164
|
client: Any,
|
|
1062
1165
|
helper_type: str,
|
|
1063
1166
|
config_dict: dict[str, Any],
|
|
1167
|
+
entry_id: str,
|
|
1064
1168
|
) -> dict[str, Any]:
|
|
1065
|
-
"""
|
|
1169
|
+
"""Update an existing flow-based helper via its options flow.
|
|
1066
1170
|
|
|
1067
|
-
|
|
1068
|
-
Aborts the flow on error.
|
|
1171
|
+
Verifies the entry domain matches helper_type, starts an options flow,
|
|
1172
|
+
walks the flow steps, and returns the result. Aborts the flow on error.
|
|
1069
1173
|
"""
|
|
1070
|
-
|
|
1174
|
+
return await update_config_entry_options(
|
|
1175
|
+
client,
|
|
1176
|
+
entry_id,
|
|
1177
|
+
config_dict,
|
|
1178
|
+
expected_domain=helper_type,
|
|
1179
|
+
noun="helper",
|
|
1180
|
+
)
|
|
1181
|
+
|
|
1182
|
+
|
|
1183
|
+
async def create_config_entry(
|
|
1184
|
+
client: Any,
|
|
1185
|
+
domain: str,
|
|
1186
|
+
config_dict: dict[str, Any],
|
|
1187
|
+
*,
|
|
1188
|
+
noun: str = "integration",
|
|
1189
|
+
) -> dict[str, Any]:
|
|
1190
|
+
"""Create a config entry by driving ``domain``'s config flow.
|
|
1191
|
+
|
|
1192
|
+
Starts a config flow, walks the flow steps (menus and multi-step forms),
|
|
1193
|
+
and returns the result. Aborts the flow on error. ``noun`` only affects
|
|
1194
|
+
response wording.
|
|
1195
|
+
"""
|
|
1196
|
+
flow_result = await client.start_config_flow(domain)
|
|
1071
1197
|
flow_id = flow_result.get("flow_id")
|
|
1072
1198
|
|
|
1073
1199
|
if not flow_id:
|
|
@@ -1076,9 +1202,9 @@ async def create_flow_helper(
|
|
|
1076
1202
|
ErrorCode.SERVICE_CALL_FAILED,
|
|
1077
1203
|
"Failed to start config flow",
|
|
1078
1204
|
suggestions=[
|
|
1079
|
-
"Check that the
|
|
1205
|
+
f"Check that the {noun} domain exists and Home Assistant is reachable"
|
|
1080
1206
|
],
|
|
1081
|
-
context={"
|
|
1207
|
+
context={"domain": domain, "details": flow_result},
|
|
1082
1208
|
)
|
|
1083
1209
|
)
|
|
1084
1210
|
|
|
@@ -1088,7 +1214,7 @@ async def create_flow_helper(
|
|
|
1088
1214
|
flow_id,
|
|
1089
1215
|
flow_result,
|
|
1090
1216
|
config_dict,
|
|
1091
|
-
helper_type=
|
|
1217
|
+
helper_type=domain,
|
|
1092
1218
|
)
|
|
1093
1219
|
except Exception:
|
|
1094
1220
|
try:
|
|
@@ -1104,9 +1230,22 @@ async def create_flow_helper(
|
|
|
1104
1230
|
"success": True,
|
|
1105
1231
|
"entry_id": entry.get("entry_id"),
|
|
1106
1232
|
"title": entry.get("title"),
|
|
1107
|
-
"domain":
|
|
1108
|
-
"message": f"{
|
|
1233
|
+
"domain": domain,
|
|
1234
|
+
"message": f"{domain} {noun} created successfully",
|
|
1109
1235
|
}
|
|
1110
1236
|
if result.get("warnings"):
|
|
1111
1237
|
response["warnings"] = result["warnings"]
|
|
1112
1238
|
return response
|
|
1239
|
+
|
|
1240
|
+
|
|
1241
|
+
async def create_flow_helper(
|
|
1242
|
+
client: Any,
|
|
1243
|
+
helper_type: str,
|
|
1244
|
+
config_dict: dict[str, Any],
|
|
1245
|
+
) -> dict[str, Any]:
|
|
1246
|
+
"""Create a new flow-based helper via the config flow.
|
|
1247
|
+
|
|
1248
|
+
Starts a config flow, walks the flow steps, and returns the result.
|
|
1249
|
+
Aborts the flow on error.
|
|
1250
|
+
"""
|
|
1251
|
+
return await create_config_entry(client, helper_type, config_dict, noun="helper")
|