ha-mcp-dev 7.6.0.dev616__tar.gz → 7.6.0.dev618__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.dev616/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.6.0.dev618}/PKG-INFO +1 -1
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/pyproject.toml +1 -1
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/best_practice_checker.py +42 -7
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_entities.py +4 -4
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_service.py +2 -2
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/LICENSE +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/MANIFEST.in +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/README.md +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/setup.cfg +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/__main__.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/_pypi_marker +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/_version.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/auth/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/auth/consent_form.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/auth/provider.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/backup_manager.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/client/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/client/rest_client.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/client/supervisor_client.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/client/websocket_client.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/client/websocket_listener.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/config.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/errors.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/policy/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/policy/approval_queue.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/policy/evaluator.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/policy/handlers.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/policy/middleware.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/policy/model.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/policy/persistence.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/policy/value_sources.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/py.typed +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/server.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/settings_ui.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/smoke_test.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/auto_backup.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/backup.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/device_control.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/enhanced.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/helpers.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/reference_validator.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/registry.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/smart_search.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_addons.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_areas.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_blueprints.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_bug_report.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_calendar.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_camera.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_categories.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_code.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_config_automations.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_config_entry_flow.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_energy.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_filesystem.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_groups.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_hacs.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_history.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_integrations.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_labels.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_registry.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_resources.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_search.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_services.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_system.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_todo.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_traces.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_updates.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_utility.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_zones.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/util_helpers.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/transforms/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/transforms/categorized_search.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/utils/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/utils/config_hash.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/utils/data_paths.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/utils/domain_handlers.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/utils/fuzzy_search.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/utils/operation_manager.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/utils/python_sandbox.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/utils/usage_logger.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/tests/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/tests/test_constants.py +0 -0
- {ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/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.6.0.
|
|
7
|
+
version = "7.6.0.dev618"
|
|
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"
|
{ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/best_practice_checker.py
RENAMED
|
@@ -78,11 +78,34 @@ _RE_STATE_IN = re.compile(r"states\s*\([^)]+\)\s+in\s+[\[(]")
|
|
|
78
78
|
# Unsafe direct state access: states.sensor.x.state
|
|
79
79
|
_RE_DIRECT_STATE = re.compile(r"\bstates\.\w+\.\w+\.state\b")
|
|
80
80
|
# Duration/recency checks via last_changed or last_updated arithmetic.
|
|
81
|
-
#
|
|
82
|
-
#
|
|
81
|
+
# Catches the shapes that compute "how long since X changed", all of which map
|
|
82
|
+
# to the native ``for:`` field:
|
|
83
|
+
# now() - X.last_changed (forward subtraction)
|
|
84
|
+
# X.last_changed (<|<=|>|>=) now() - <delta> (reversed; the subtraction is
|
|
85
|
+
# required — a bare ``X.last_changed < now()`` is *always* true and carries
|
|
86
|
+
# no duration, so it is intentionally NOT flagged: ``for:`` cannot express it)
|
|
87
|
+
# now() (<|<=|>|>=) X.last_changed + <delta> (now() on the left)
|
|
88
|
+
# X.last_changed + <delta> (<|<=|>|>=) now() (delta added to the attribute)
|
|
89
|
+
# now().timestamp() - X.last_changed.timestamp() (epoch subtraction)
|
|
90
|
+
# as_timestamp(now()) - as_timestamp(X.last_changed) (function form)
|
|
91
|
+
# as_timestamp(now()) - X.last_changed | as_timestamp (filter form)
|
|
92
|
+
# Every alternation requires a dotted qualifier ending on a word boundary, so
|
|
93
|
+
# bare Jinja variables literally named ``last_changed`` and longer look-alike
|
|
94
|
+
# attributes (``last_changed_at``) are not falsely flagged; a leading ``word.``
|
|
95
|
+
# (``trigger.``, ``states.sensor.x.``) is the minimum.
|
|
96
|
+
# Intentionally NOT matched (heuristic limits, low value): the reversed
|
|
97
|
+
# as_timestamp operand order, the reversed ``.timestamp()`` order, and
|
|
98
|
+
# ``state_attr(e, 'last_changed')`` / ``states('e').last_changed`` — the latter
|
|
99
|
+
# two are not valid ways to read a state's ``last_changed`` in HA anyway. These
|
|
100
|
+
# fall through to the generic template fallback in condition/trigger positions.
|
|
83
101
|
_RE_DURATION_MATH = re.compile(
|
|
84
102
|
r"\bnow\(\)\s*-\s*(?:\w+\.)+last_(?:changed|updated)\b"
|
|
85
|
-
r"|\b(?:\w+\.)+last_(?:changed|updated)\s
|
|
103
|
+
r"|\b(?:\w+\.)+last_(?:changed|updated)\b\s*[<>]=?\s*now\(\)\s*-"
|
|
104
|
+
r"|\bnow\(\)\s*[<>]=?\s*(?:\w+\.)+last_(?:changed|updated)\b\s*\+"
|
|
105
|
+
r"|\b(?:\w+\.)+last_(?:changed|updated)\b\s*\+\s*[^<>{}]+?[<>]=?\s*now\(\)"
|
|
106
|
+
r"|\bnow\(\)\.timestamp\(\)\s*-\s*(?:\w+\.)+last_(?:changed|updated)\.timestamp\(\)"
|
|
107
|
+
r"|\bas_timestamp\(\s*now\(\)\s*\)\s*-\s*as_timestamp\([^)]*\.last_(?:changed|updated)\b"
|
|
108
|
+
r"|\bas_timestamp\(\s*now\(\)\s*\)\s*-\s*(?:\w+\.)+last_(?:changed|updated)\b\s*\|\s*as_timestamp\b"
|
|
86
109
|
)
|
|
87
110
|
# Motion entity pattern
|
|
88
111
|
_RE_MOTION = re.compile(r"binary_sensor\.\w*motion", re.IGNORECASE)
|
|
@@ -220,7 +243,15 @@ def _check_template_string(
|
|
|
220
243
|
initial_count = len(warnings)
|
|
221
244
|
label = position.capitalize()
|
|
222
245
|
|
|
223
|
-
|
|
246
|
+
# Duration/recency math (e.g. `(now() - X.last_changed).total_seconds() > 300`)
|
|
247
|
+
# also contains a numeric comparison, so it matches `_RE_NUMERIC_CMP` too. But its
|
|
248
|
+
# correct native replacement is the `for:` field, NOT `numeric_state`. Suppress the
|
|
249
|
+
# numeric_state suggestion when duration math is present so the user isn't handed
|
|
250
|
+
# two conflicting native alternatives for one template (the duration warning below
|
|
251
|
+
# fires instead).
|
|
252
|
+
duration_match = _RE_DURATION_MATH.search(template)
|
|
253
|
+
|
|
254
|
+
if _RE_NUMERIC_CMP.search(template) and not duration_match:
|
|
224
255
|
warnings.append(
|
|
225
256
|
f"{label} uses template with float/int comparison — use native "
|
|
226
257
|
f"`numeric_state` {position} instead "
|
|
@@ -280,7 +311,7 @@ def _check_template_string(
|
|
|
280
311
|
"function instead (returns 'unknown' if missing rather than raising)."
|
|
281
312
|
+ _ref(skill_prefix, "template-guidelines.md#common-patterns")
|
|
282
313
|
)
|
|
283
|
-
if
|
|
314
|
+
if duration_match:
|
|
284
315
|
warnings.append(
|
|
285
316
|
f"{label} uses template for duration/recency check "
|
|
286
317
|
"(`now() - X.last_changed/last_updated`) — use the native `for:` field "
|
|
@@ -502,7 +533,11 @@ def _check_triggers(
|
|
|
502
533
|
vt = trigger.get("value_template", "")
|
|
503
534
|
if isinstance(vt, str):
|
|
504
535
|
initial = len(warnings)
|
|
505
|
-
|
|
536
|
+
# See `_check_template_string`: duration math also trips the numeric
|
|
537
|
+
# comparison detector, but maps to `for:`, not `numeric_state`. Suppress
|
|
538
|
+
# the numeric_state suggestion when duration math is present.
|
|
539
|
+
duration_match = _RE_DURATION_MATH.search(vt)
|
|
540
|
+
if _RE_NUMERIC_CMP.search(vt) and not duration_match:
|
|
506
541
|
warnings.append(
|
|
507
542
|
"Trigger uses template with float/int comparison — "
|
|
508
543
|
"use native `numeric_state` trigger instead "
|
|
@@ -522,7 +557,7 @@ def _check_triggers(
|
|
|
522
557
|
"automation-patterns.md#trigger-types",
|
|
523
558
|
)
|
|
524
559
|
)
|
|
525
|
-
if
|
|
560
|
+
if duration_match:
|
|
526
561
|
warnings.append(
|
|
527
562
|
"Trigger uses template for duration/recency check "
|
|
528
563
|
"(`now() - X.last_changed/last_updated`) — use the native "
|
|
@@ -613,12 +613,12 @@ def register_entity_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
613
613
|
),
|
|
614
614
|
] = None,
|
|
615
615
|
options: Annotated[
|
|
616
|
-
|
|
616
|
+
dict[str, dict[str, Any]] | None,
|
|
617
617
|
Field(
|
|
618
618
|
description=(
|
|
619
619
|
"Per-domain entity registry options (e.g. sensor 'display_precision', "
|
|
620
620
|
"weather 'forecast_type'). Pass a dict mapping domain to a sub-dict, "
|
|
621
|
-
'e.g. {"sensor": {"display_precision": 2}}.
|
|
621
|
+
'e.g. {"sensor": {"display_precision": 2}}. '
|
|
622
622
|
"Multiple domains are sent as separate registry updates. "
|
|
623
623
|
"For 'Show As' use the dedicated `device_class` parameter — that is "
|
|
624
624
|
"what the HA UI Show As dropdown writes. Voice-assistant exposure is "
|
|
@@ -658,7 +658,7 @@ def register_entity_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
658
658
|
),
|
|
659
659
|
] = None,
|
|
660
660
|
categories: Annotated[
|
|
661
|
-
|
|
661
|
+
dict[str, str | None] | None,
|
|
662
662
|
Field(
|
|
663
663
|
description=(
|
|
664
664
|
"Category assignment as a dict mapping scope to category_id. "
|
|
@@ -684,7 +684,7 @@ def register_entity_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
684
684
|
),
|
|
685
685
|
] = "set",
|
|
686
686
|
expose_to: Annotated[
|
|
687
|
-
|
|
687
|
+
dict[str, bool] | None,
|
|
688
688
|
Field(
|
|
689
689
|
description=(
|
|
690
690
|
"Control voice assistant exposure. Pass a dict mapping assistant IDs to booleans. "
|
|
@@ -289,7 +289,7 @@ class ServiceTools:
|
|
|
289
289
|
domain: str,
|
|
290
290
|
service: str,
|
|
291
291
|
entity_id: str | None = None,
|
|
292
|
-
data:
|
|
292
|
+
data: dict[str, Any] | None = None,
|
|
293
293
|
return_response: bool | str = False,
|
|
294
294
|
wait: bool | str = True,
|
|
295
295
|
verbose: Annotated[
|
|
@@ -629,7 +629,7 @@ class ServiceTools:
|
|
|
629
629
|
async def ha_call_event(
|
|
630
630
|
self,
|
|
631
631
|
event_type: str,
|
|
632
|
-
data:
|
|
632
|
+
data: dict[str, Any] | None = None,
|
|
633
633
|
) -> dict[str, Any]:
|
|
634
634
|
"""Execute a custom event on the Home Assistant event bus.
|
|
635
635
|
|
|
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
|
|
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.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/AGENTS.md
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/CLAUDE.md
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/resources/skills-vendor/LICENSE
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/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
|
|
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.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_config_automations.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_config_dashboards.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_config_entry_flow.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_config_helpers.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_config_scripts.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
|
{ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/tools/tools_voice_assistant.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/transforms/categorized_search.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/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.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp/utils/kill_signal_diagnostics.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/src/ha_mcp_dev.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev616 → ha_mcp_dev-7.6.0.dev618}/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
|
|
File without changes
|