ha-mcp-dev 7.8.0.dev705__tar.gz → 7.8.0.dev706__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 (143) hide show
  1. {ha_mcp_dev-7.8.0.dev705/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.8.0.dev706}/PKG-INFO +2 -1
  2. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/pyproject.toml +2 -1
  3. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/util_helpers.py +75 -16
  4. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706/src/ha_mcp_dev.egg-info}/PKG-INFO +2 -1
  5. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp_dev.egg-info/requires.txt +1 -0
  6. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/LICENSE +0 -0
  7. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/MANIFEST.in +0 -0
  8. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/README.md +0 -0
  9. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/setup.cfg +0 -0
  10. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/__init__.py +0 -0
  11. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/__main__.py +0 -0
  12. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/_pypi_marker +0 -0
  13. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/_version.py +0 -0
  14. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/auth/__init__.py +0 -0
  15. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/auth/consent_form.py +0 -0
  16. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/auth/provider.py +0 -0
  17. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/backup_manager.py +0 -0
  18. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/client/__init__.py +0 -0
  19. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/client/rest_client.py +0 -0
  20. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/client/supervisor_client.py +0 -0
  21. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/client/websocket_client.py +0 -0
  22. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/client/websocket_listener.py +0 -0
  23. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/config.py +0 -0
  24. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
  25. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
  26. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
  27. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/errors.py +0 -0
  28. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/policy/__init__.py +0 -0
  29. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/policy/approval_queue.py +0 -0
  30. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/policy/evaluator.py +0 -0
  31. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/policy/handlers.py +0 -0
  32. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/policy/middleware.py +0 -0
  33. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/policy/model.py +0 -0
  34. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/policy/persistence.py +0 -0
  35. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/policy/value_sources.py +0 -0
  36. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/py.typed +0 -0
  37. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/read_only.py +0 -0
  38. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  39. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  40. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  41. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  42. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
  43. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  44. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  45. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  46. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  47. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  48. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  49. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
  50. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  51. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
  52. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
  53. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  54. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
  55. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  56. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  57. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  58. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  59. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
  60. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/server.py +0 -0
  61. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/settings.css +0 -0
  62. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/settings.js +0 -0
  63. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/settings_ui.py +0 -0
  64. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/smoke_test.py +0 -0
  65. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
  66. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/__init__.py +0 -0
  67. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/auto_backup.py +0 -0
  68. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/backup.py +0 -0
  69. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/best_practice_checker.py +0 -0
  70. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/config_entry_flow.py +0 -0
  71. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/device_control.py +0 -0
  72. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/enhanced.py +0 -0
  73. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/helpers.py +0 -0
  74. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/reference_validator.py +0 -0
  75. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/registry.py +0 -0
  76. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
  77. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/smart_search/_base.py +0 -0
  78. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/smart_search/_config.py +0 -0
  79. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
  80. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
  81. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
  82. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
  83. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
  84. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
  85. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tool_search_hint_middleware.py +0 -0
  86. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_addons.py +0 -0
  87. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_areas.py +0 -0
  88. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  89. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_bug_report.py +0 -0
  90. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_calendar.py +0 -0
  91. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_camera.py +0 -0
  92. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_categories.py +0 -0
  93. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_code.py +0 -0
  94. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_config_automations.py +0 -0
  95. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
  96. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
  97. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
  98. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
  99. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
  100. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_energy.py +0 -0
  101. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_entities.py +0 -0
  102. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_filesystem.py +0 -0
  103. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_groups.py +0 -0
  104. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_hacs.py +0 -0
  105. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_history.py +0 -0
  106. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_integrations.py +0 -0
  107. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_labels.py +0 -0
  108. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
  109. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_registry.py +0 -0
  110. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_resources.py +0 -0
  111. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_search.py +0 -0
  112. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_service.py +0 -0
  113. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_services.py +0 -0
  114. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_system.py +0 -0
  115. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_themes.py +0 -0
  116. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_todo.py +0 -0
  117. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_traces.py +0 -0
  118. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_updates.py +0 -0
  119. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_utility.py +0 -0
  120. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  121. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
  122. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/tools_zones.py +0 -0
  123. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/tools/validation_middleware.py +0 -0
  124. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/transforms/__init__.py +0 -0
  125. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/transforms/categorized_search.py +0 -0
  126. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
  127. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/utils/__init__.py +0 -0
  128. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/utils/config_hash.py +0 -0
  129. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/utils/data_paths.py +0 -0
  130. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/utils/domain_handlers.py +0 -0
  131. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  132. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
  133. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/utils/operation_manager.py +0 -0
  134. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/utils/python_sandbox.py +0 -0
  135. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/utils/skill_loader.py +0 -0
  136. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp/utils/usage_logger.py +0 -0
  137. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
  138. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
  139. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
  140. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
  141. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/tests/__init__.py +0 -0
  142. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/tests/test_constants.py +0 -0
  143. {ha_mcp_dev-7.8.0.dev705 → ha_mcp_dev-7.8.0.dev706}/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.8.0.dev705
3
+ Version: 7.8.0.dev706
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
@@ -26,6 +26,7 @@ Requires-Dist: truststore==0.10.4
26
26
  Requires-Dist: websockets==16.0
27
27
  Requires-Dist: cryptography==49.0.0
28
28
  Requires-Dist: pydantic-monty==0.0.18
29
+ Requires-Dist: tzdata>=2024.1
29
30
  Dynamic: license-file
30
31
 
31
32
  > **Breaking change (v7.3.0):** `ha_config_set_yaml` has been moved to [beta](docs/beta.md).
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ha-mcp-dev"
7
- version = "7.8.0.dev705"
7
+ version = "7.8.0.dev706"
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"
@@ -32,6 +32,7 @@ dependencies = [
32
32
  "websockets==16.0",
33
33
  "cryptography==49.0.0",
34
34
  "pydantic-monty==0.0.18",
35
+ "tzdata>=2024.1",
35
36
  ]
36
37
 
37
38
  [project.urls]
@@ -10,7 +10,10 @@ import logging
10
10
  import re
11
11
  import time
12
12
  from collections.abc import Awaitable, Callable
13
+ from datetime import UTC, datetime
14
+ from datetime import tzinfo as _TZInfo
13
15
  from typing import Any
16
+ from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
14
17
 
15
18
  from fastmcp.exceptions import ToolError
16
19
  from pydantic import BeforeValidator, ValidationError
@@ -596,26 +599,30 @@ async def get_logger_levels(client: Any) -> dict[str, dict[str, Any]]:
596
599
  async def add_timezone_metadata(
597
600
  client: Any, data: dict[str, Any], include_metadata: bool = True
598
601
  ) -> dict[str, Any]:
599
- """Add Home Assistant timezone to tool responses for local time context.
602
+ """Add Home Assistant timezone to tool responses and convert timestamps to local time.
600
603
 
601
- Wraps *data* in ``{"data": ..., "metadata": {...}}``. Pass
602
- ``include_metadata=False`` to return *data* unchanged — the ``metadata``
603
- wrapper is then omitted entirely.
604
+ Fetches ``time_zone`` from ``/api/config``, converts every
605
+ ``last_changed``, ``last_updated``, ``last_reported``, ``when``, and
606
+ ``last_triggered`` field found anywhere in *data* from UTC to that local
607
+ timezone, then wraps the result in ``{"data": ..., "metadata": {...}}``.
608
+
609
+ Pass ``include_metadata=False`` to return *data* unchanged — the
610
+ ``metadata`` wrapper is then omitted entirely.
611
+
612
+ Conversion notes:
613
+ - Offset-aware strings (``+00:00``) are converted directly.
614
+ - Naive strings (no offset) are assumed to be UTC before conversion.
615
+ - ``ZoneInfoNotFoundError`` (tzdata not installed) falls back to UTC.
616
+ - Any config-fetch failure also falls back to UTC without conversion.
604
617
  """
605
618
  if not include_metadata:
606
619
  return data
620
+
621
+ ha_timezone = "UTC"
622
+ fetch_failed = False
607
623
  try:
608
624
  config = await client.get_config()
609
625
  ha_timezone = config.get("time_zone", "UTC")
610
-
611
- return {
612
- "data": data,
613
- "metadata": {
614
- "home_assistant_timezone": ha_timezone,
615
- "timestamp_format": "ISO 8601 (UTC)",
616
- "note": f"All timestamps are in UTC. Home Assistant timezone is {ha_timezone}.",
617
- },
618
- }
619
626
  except (
620
627
  HomeAssistantConnectionError,
621
628
  HomeAssistantAPIError,
@@ -623,21 +630,73 @@ async def add_timezone_metadata(
623
630
  TimeoutError,
624
631
  OSError,
625
632
  ) as _tz_exc:
633
+ fetch_failed = True
626
634
  logger.warning(
627
635
  "add_timezone_metadata: failed to fetch HA timezone config — "
628
- "falling back to 'Unknown': %s",
636
+ "falling back to UTC: %s",
629
637
  _tz_exc,
630
638
  exc_info=True,
631
639
  )
640
+
641
+ if fetch_failed:
632
642
  return {
633
643
  "data": data,
634
644
  "metadata": {
635
- "home_assistant_timezone": "Unknown",
645
+ "home_assistant_timezone": "UTC",
636
646
  "timestamp_format": "ISO 8601 (UTC)",
637
- "note": "All timestamps are in UTC. Could not fetch Home Assistant timezone.",
647
+ "note": "Could not fetch Home Assistant timezone — timestamps are in UTC.",
638
648
  },
639
649
  }
640
650
 
651
+ try:
652
+ local_tz: _TZInfo = ZoneInfo(ha_timezone)
653
+ except ZoneInfoNotFoundError:
654
+ logger.warning(
655
+ "add_timezone_metadata: ZoneInfo(%r) not found "
656
+ "(tzdata package missing?) — falling back to UTC",
657
+ ha_timezone,
658
+ )
659
+ local_tz = UTC
660
+ ha_timezone = "UTC"
661
+
662
+ _TS_FIELDS = {
663
+ "last_changed",
664
+ "last_updated",
665
+ "last_reported",
666
+ "when",
667
+ "last_triggered",
668
+ }
669
+
670
+ def _convert(obj: Any) -> Any:
671
+ if isinstance(obj, list):
672
+ return [_convert(i) for i in obj]
673
+ if isinstance(obj, dict):
674
+ out = {}
675
+ for k, v in obj.items():
676
+ if k in _TS_FIELDS and isinstance(v, str) and v:
677
+ try:
678
+ parsed = datetime.fromisoformat(v)
679
+ if parsed.tzinfo is None:
680
+ parsed = parsed.replace(tzinfo=UTC)
681
+ out[k] = parsed.astimezone(local_tz).isoformat()
682
+ except (ValueError, TypeError):
683
+ out[k] = v
684
+ else:
685
+ out[k] = _convert(v)
686
+ return out
687
+ return obj
688
+
689
+ converted_data = _convert(data)
690
+
691
+ return {
692
+ "data": converted_data,
693
+ "metadata": {
694
+ "home_assistant_timezone": ha_timezone,
695
+ "timestamp_format": f"ISO 8601 ({ha_timezone})",
696
+ "note": f"Per-record timestamp fields (last_changed, last_updated, last_reported, when, last_triggered) have been converted to {ha_timezone} local time. Query-window boundary fields (period, start_time, end_time) remain in UTC.",
697
+ },
698
+ }
699
+
641
700
 
642
701
  # --- WS-event-driven wait helpers (#1152) -----------------------------------
643
702
  #
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ha-mcp-dev
3
- Version: 7.8.0.dev705
3
+ Version: 7.8.0.dev706
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
@@ -26,6 +26,7 @@ Requires-Dist: truststore==0.10.4
26
26
  Requires-Dist: websockets==16.0
27
27
  Requires-Dist: cryptography==49.0.0
28
28
  Requires-Dist: pydantic-monty==0.0.18
29
+ Requires-Dist: tzdata>=2024.1
29
30
  Dynamic: license-file
30
31
 
31
32
  > **Breaking change (v7.3.0):** `ha_config_set_yaml` has been moved to [beta](docs/beta.md).
@@ -6,3 +6,4 @@ truststore==0.10.4
6
6
  websockets==16.0
7
7
  cryptography==49.0.0
8
8
  pydantic-monty==0.0.18
9
+ tzdata>=2024.1