ha-mcp-dev 7.4.1.dev459__tar.gz → 7.4.1.dev461__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.
Files changed (108) hide show
  1. {ha_mcp_dev-7.4.1.dev459/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.4.1.dev461}/PKG-INFO +1 -1
  2. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/pyproject.toml +1 -1
  3. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_config_entry_flow.py +121 -13
  4. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_config_helpers.py +940 -273
  5. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
  6. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/LICENSE +0 -0
  7. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/MANIFEST.in +0 -0
  8. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/README.md +0 -0
  9. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/setup.cfg +0 -0
  10. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/__init__.py +0 -0
  11. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/__main__.py +0 -0
  12. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/_pypi_marker +0 -0
  13. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/_version.py +0 -0
  14. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/auth/__init__.py +0 -0
  15. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/auth/consent_form.py +0 -0
  16. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/auth/provider.py +0 -0
  17. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/client/__init__.py +0 -0
  18. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/client/rest_client.py +0 -0
  19. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/client/websocket_client.py +0 -0
  20. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/client/websocket_listener.py +0 -0
  21. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/config.py +0 -0
  22. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/errors.py +0 -0
  23. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/py.typed +0 -0
  24. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  25. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  26. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  27. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  28. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  29. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  30. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  31. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  32. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  33. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  34. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
  35. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  36. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
  37. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
  38. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  39. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
  40. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  41. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  42. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  43. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  44. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/server.py +0 -0
  45. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/settings_ui.py +0 -0
  46. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/smoke_test.py +0 -0
  47. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/__init__.py +0 -0
  48. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/backup.py +0 -0
  49. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/best_practice_checker.py +0 -0
  50. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/device_control.py +0 -0
  51. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/enhanced.py +0 -0
  52. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/helpers.py +0 -0
  53. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/reference_validator.py +0 -0
  54. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/registry.py +0 -0
  55. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/smart_search.py +0 -0
  56. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_addons.py +0 -0
  57. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_areas.py +0 -0
  58. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  59. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_bug_report.py +0 -0
  60. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_calendar.py +0 -0
  61. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_camera.py +0 -0
  62. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_categories.py +0 -0
  63. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_code.py +0 -0
  64. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_config_automations.py +0 -0
  65. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
  66. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
  67. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_energy.py +0 -0
  68. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_entities.py +0 -0
  69. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_filesystem.py +0 -0
  70. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_groups.py +0 -0
  71. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_hacs.py +0 -0
  72. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_history.py +0 -0
  73. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_integrations.py +0 -0
  74. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_labels.py +0 -0
  75. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
  76. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_registry.py +0 -0
  77. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_resources.py +0 -0
  78. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_search.py +0 -0
  79. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_service.py +0 -0
  80. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_services.py +0 -0
  81. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_system.py +0 -0
  82. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_todo.py +0 -0
  83. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_traces.py +0 -0
  84. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_updates.py +0 -0
  85. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_utility.py +0 -0
  86. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  87. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
  88. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/tools_zones.py +0 -0
  89. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/tools/util_helpers.py +0 -0
  90. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/transforms/__init__.py +0 -0
  91. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/transforms/categorized_search.py +0 -0
  92. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/utils/__init__.py +0 -0
  93. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/utils/config_hash.py +0 -0
  94. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/utils/data_paths.py +0 -0
  95. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/utils/domain_handlers.py +0 -0
  96. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  97. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
  98. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/utils/operation_manager.py +0 -0
  99. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/utils/python_sandbox.py +0 -0
  100. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp/utils/usage_logger.py +0 -0
  101. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
  102. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
  103. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
  104. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
  105. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
  106. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/tests/__init__.py +0 -0
  107. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/tests/test_constants.py +0 -0
  108. {ha_mcp_dev-7.4.1.dev459 → ha_mcp_dev-7.4.1.dev461}/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.4.1.dev459
3
+ Version: 7.4.1.dev461
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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ha-mcp-dev"
7
- version = "7.4.1.dev459"
7
+ version = "7.4.1.dev461"
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"
@@ -69,6 +69,41 @@ FLOW_HELPER_TYPES: frozenset[str] = frozenset({
69
69
  "generic_hygrostat",
70
70
  })
71
71
 
72
+ # Issue #1149: full set accepted by ha_get_helper_schema (15 flow + 12
73
+ # simple). Simple types route to a static dict in tools_config_helpers
74
+ # rather than starting an HA flow.
75
+ ALL_HELPER_TYPES = Literal[
76
+ # Flow helpers (mirrors SUPPORTED_HELPERS above)
77
+ "template",
78
+ "group",
79
+ "utility_meter",
80
+ "derivative",
81
+ "min_max",
82
+ "threshold",
83
+ "integration",
84
+ "statistics",
85
+ "trend",
86
+ "random",
87
+ "filter",
88
+ "tod",
89
+ "generic_thermostat",
90
+ "switch_as_x",
91
+ "generic_hygrostat",
92
+ # Simple helpers (mirrors SIMPLE_HELPER_TYPES in tools_config_helpers)
93
+ "input_button",
94
+ "input_boolean",
95
+ "input_select",
96
+ "input_number",
97
+ "input_text",
98
+ "input_datetime",
99
+ "counter",
100
+ "timer",
101
+ "schedule",
102
+ "zone",
103
+ "person",
104
+ "tag",
105
+ ]
106
+
72
107
  # Keys used to specify a menu selection — stripped before submitting form data.
73
108
  _MENU_SELECTION_KEYS = frozenset({"group_type", "next_step_id", "menu_option"})
74
109
 
@@ -265,6 +300,10 @@ async def _fetch_data_schema_for_error_context(
265
300
  user step's ``data_schema`` so the LLM has something concrete to react
266
301
  to when HA's error body is unstructured. Returns ``None`` on any
267
302
  failure or when the helper is menu-based without a chosen branch.
303
+
304
+ Public alias ``fetch_helper_data_schema`` is exported below for the
305
+ pre-flow validation gates in ``_handle_flow_helper`` (issue #1149) —
306
+ they need the same best-effort fetch but live in another module.
268
307
  """
269
308
  if not helper_type or client is None:
270
309
  return None
@@ -306,6 +345,13 @@ async def _fetch_data_schema_for_error_context(
306
345
  )
307
346
 
308
347
 
348
+ # Public alias for use by pre-flow validation gates in tools_config_helpers
349
+ # (issue #1149). The underscore-prefixed original is kept to preserve the
350
+ # call sites already in this module; the alias avoids importing a private
351
+ # name across modules.
352
+ fetch_helper_data_schema = _fetch_data_schema_for_error_context
353
+
354
+
309
355
  async def _raise_flow_api_error(
310
356
  api_error: HomeAssistantAPIError,
311
357
  *,
@@ -355,6 +401,16 @@ async def _raise_flow_api_error(
355
401
  suggestions.append(
356
402
  "Fix the field(s) listed in 'field_errors' and retry the call."
357
403
  )
404
+ # Issue #1149: also attach the data_schema so the LLM sees the field
405
+ # shape (selector, required, ...) alongside the per-field error
406
+ # codes — symmetric with the unstructured-error branch below.
407
+ # `field_errors` tells "what failed", `data_schema` tells "what's
408
+ # accepted"; together they're enough for self-correction.
409
+ schema = await _fetch_data_schema_for_error_context(
410
+ client, helper_type, menu_choice
411
+ )
412
+ if schema is not None:
413
+ context["data_schema"] = schema
358
414
  else:
359
415
  # Unstructured — attach the data_schema so the LLM has something to use.
360
416
  message = (
@@ -670,13 +726,14 @@ class ConfigEntryFlowTools:
670
726
  @log_tool_usage
671
727
  async def ha_get_helper_schema(
672
728
  self,
673
- helper_type: Annotated[SUPPORTED_HELPERS, Field(description="Helper type")],
729
+ helper_type: Annotated[ALL_HELPER_TYPES, Field(description="Helper type")],
674
730
  menu_option: Annotated[
675
731
  str | None,
676
732
  Field(
677
733
  description=(
678
- "For menu-based helpers: the sub-type to inspect (e.g. 'sensor' or "
679
- "'binary_sensor' for template). Omit to see available menu options first."
734
+ "For menu-based flow helpers (template, group): the sub-type to "
735
+ "inspect (e.g. 'sensor' or 'binary_sensor' for template). Omit to "
736
+ "see available menu options first. Ignored for simple helpers."
680
737
  ),
681
738
  default=None,
682
739
  ),
@@ -684,21 +741,72 @@ class ConfigEntryFlowTools:
684
741
  ) -> dict[str, Any]:
685
742
  """Get configuration schema for a helper type.
686
743
 
687
- Returns the form fields and their types needed to create this helper.
688
- Use before ha_config_set_helper to understand required config.
744
+ Returns the field list and types needed to create this helper. Use
745
+ before ha_config_set_helper when unsure of the required `config`
746
+ (flow helpers) or required typed parameters (simple helpers). The
747
+ same schema is also auto-attached to validation-error responses
748
+ from ha_config_set_helper, so an explicit pre-call is optional.
689
749
 
690
- Two-call workflow for menu-based helpers (template, group):
750
+ Three branches:
691
751
 
692
- # Step 1 discover sub-types:
693
- ha_get_helper_schema("template")
694
- → {flow_type: "menu", menu_options: ["sensor", "binary_sensor", ...]}
752
+ 1. Simple helpers (input_*, counter, timer, schedule, zone, person,
753
+ tag): static schema returned from a built-in dict.
754
+ ha_get_helper_schema("input_select")
755
+ → {flow_type: "form", data_schema: [{name: "name", required: True, ...}, ...]}
695
756
 
696
- # Step 2 inspect form fields for a sub-type:
697
- ha_get_helper_schema("template", menu_option="sensor")
698
- → {flow_type: "form", menu_option: "sensor", data_schema: [{name: "state", ...}, ...]}
757
+ 2. Form-based flow helpers (min_max, utility_meter, statistics, ...):
758
+ starts a fresh HA flow, reads the schema, and aborts the flow.
759
+ ha_get_helper_schema("min_max")
760
+ → {flow_type: "form", data_schema: [...]}
699
761
 
700
- For form-based helpers (min_max, utility_meter, etc.), omit menu_option.
762
+ 3. Menu-based flow helpers (template, group): two-call workflow.
763
+ # Step 1 — discover sub-types:
764
+ ha_get_helper_schema("template")
765
+ → {flow_type: "menu", menu_options: ["sensor", "binary_sensor", ...]}
766
+
767
+ # Step 2 — inspect form fields for a sub-type:
768
+ ha_get_helper_schema("template", menu_option="sensor")
769
+ → {flow_type: "form", menu_option: "sensor", data_schema: [...]}
701
770
  """
771
+ # Issue #1149: simple-helper dispatch — return a static schema
772
+ # without round-tripping HA. Lazy import keeps the existing
773
+ # tools_config_helpers ↔ tools_config_entry_flow boundary intact.
774
+ from .tools_config_helpers import (
775
+ SIMPLE_HELPER_TYPES,
776
+ get_simple_helper_schema,
777
+ )
778
+
779
+ if helper_type in SIMPLE_HELPER_TYPES:
780
+ schema = get_simple_helper_schema(helper_type)
781
+ # Invariant in tools_config_helpers asserts every simple type
782
+ # has a schema entry — None here would indicate a developer
783
+ # error that should fail loudly rather than mask as empty.
784
+ if schema is None:
785
+ raise_tool_error(create_error_response(
786
+ ErrorCode.INTERNAL_UNEXPECTED,
787
+ f"No simple-helper schema registered for '{helper_type}'",
788
+ context={"helper_type": helper_type},
789
+ ))
790
+ if menu_option is not None:
791
+ # Simple helpers have no menu — flag the misuse rather than
792
+ # silently ignore the parameter.
793
+ raise_tool_error(create_error_response(
794
+ ErrorCode.VALIDATION_INVALID_PARAMETER,
795
+ f"menu_option is not applicable to simple helper "
796
+ f"'{helper_type}' (only flow helpers like 'template' "
797
+ f"and 'group' use menus).",
798
+ suggestions=["Omit menu_option for simple helpers."],
799
+ context={"helper_type": helper_type},
800
+ ))
801
+ return {
802
+ "success": True,
803
+ "helper_type": helper_type,
804
+ "flow_type": _FlowType.FORM,
805
+ "step_id": "user",
806
+ "data_schema": schema,
807
+ "description_placeholders": {},
808
+ }
809
+
702
810
  flow_id = None # Track flow_id for error context
703
811
  try:
704
812
  flow_result = await self._client.start_config_flow(helper_type)