|
212 | 212 | CHANNEL_DEV = "dev" |
213 | 213 | DEFAULT_CHANNEL = CHANNEL_STABLE |
214 | 214 |
|
215 | | -# Automatic server-version updates. Both channels are unpinned, so an entry |
216 | | -# reload / HA restart already reinstalls the newest build; on top of that the |
217 | | -# component polls PyPI on this interval and reloads the entry when a newer build |
218 | | -# is published, so a long-running instance picks up releases without a restart. |
219 | | -# An explicit pip-spec override disables the check, as does turning off the |
220 | | -# ``auto_update`` option (OPT_AUTO_UPDATE). |
| 215 | + |
| 216 | +def dist_for_channel(channel: str) -> str: |
| 217 | + """Map a release channel to its PyPI distribution name. |
| 218 | +
|
| 219 | + The channel <-> distribution correspondence is used by the version |
| 220 | + coordinator, the auto-update notification, and the server manager's pip |
| 221 | + resolution — one shared mapping so a future third channel cannot be added |
| 222 | + to some sites and missed in others (review finding on #1760). |
| 223 | + """ |
| 224 | + return DIST_NAME_DEV if channel == CHANNEL_DEV else DIST_NAME_STABLE |
| 225 | + |
| 226 | + |
| 227 | +def channel_for_dist(dist: str) -> str: |
| 228 | + """Inverse of :func:`dist_for_channel`.""" |
| 229 | + return CHANNEL_DEV if dist == DIST_NAME_DEV else CHANNEL_STABLE |
| 230 | + |
| 231 | + |
| 232 | +# Interval of the ServerVersionCoordinator's PyPI poll (coordinator.py). The |
| 233 | +# poll itself ALWAYS runs — it feeds the `update` platform entity, which must |
| 234 | +# stay populated even when automatic updates are off (issue #1760). Whether a |
| 235 | +# newer build actually triggers a reload/reinstall is decided separately, per |
| 236 | +# refresh, in embedded_setup.async_maybe_auto_update (gated on OPT_AUTO_UPDATE |
| 237 | +# and on no pip-spec override). Only an explicit pip-spec override skips the |
| 238 | +# PyPI fetch — comparing PyPI-latest against an arbitrary pip spec is |
| 239 | +# meaningless. |
221 | 240 | UPDATE_CHECK_INTERVAL = timedelta(hours=6) |
222 | 241 |
|
223 | 242 | # PyPI JSON API for the latest published version of a distribution. ``{dist}`` |
|
227 | 246 | # Options-flow keys (stored in entry.options). |
228 | 247 | OPT_CHANNEL = "channel" |
229 | 248 | # Automatic server-version updates toggle (default on). When on, the channel is |
230 | | -# unpinned and auto-updates (force-install on reload/restart + the periodic |
231 | | -# check). When off, the server stays on the version currently installed: |
232 | | -# _resolve_pip_spec pins the channel's dist to that version and the periodic |
233 | | -# check is skipped. Governs the ha-mcp server package only — component updates |
234 | | -# still come through HACS. An explicit OPT_PIP_SPEC override wins over both. |
| 249 | +# unpinned and auto-updates (force-install on reload/restart + a reload when the |
| 250 | +# periodic check sees a newer build). When off, the server stays on the version |
| 251 | +# currently installed: _resolve_pip_spec pins the channel's dist to that version |
| 252 | +# — but the periodic PyPI check KEEPS running so the update entity still shows |
| 253 | +# newer builds; its Install button is the manual path (issue #1760). Governs the |
| 254 | +# ha-mcp server package only — component updates still come through HACS. An |
| 255 | +# explicit OPT_PIP_SPEC override wins over both and skips the check entirely. |
235 | 256 | OPT_AUTO_UPDATE = "auto_update" |
236 | 257 | DEFAULT_AUTO_UPDATE = True |
237 | 258 | OPT_SERVER_PORT = "server_port" |
|
262 | 283 | # pre-release test channel) force an actual reinstall on the next start instead |
263 | 284 | # of hitting the requirements manager's is-installed shortcut. |
264 | 285 | DATA_LAST_PIP_SPEC = "last_pip_spec" |
| 286 | +# One-shot marker set by the update entity's Install button (issue #1760): |
| 287 | +# with auto-update off, EmbeddedServerManager._resolve_pip_spec pins the |
| 288 | +# channel to the CURRENTLY installed version, so a bare reload would just |
| 289 | +# reinstall the same build. This pins the next install to a specific version |
| 290 | +# regardless of auto_update; embedded_server clears it when it CONSUMES it |
| 291 | +# (before the install attempt) — one marker buys exactly one attempt, so a |
| 292 | +# failing pinned version can never re-pin later reloads (review finding). |
| 293 | +DATA_PENDING_INSTALL_VERSION = "pending_install_version" |
265 | 294 |
|
266 | 295 | # hass.data[DOMAIN] sub-keys for the server runtime. Distinct from the tools |
267 | 296 | # entry's sub-keys ("caller_token" / "allowed_paths") so both entry types can |
|
273 | 302 | # on a genuine options change — the background bring-up persists ids/token/pip |
274 | 303 | # spec to entry.data, and those writes must not trigger a self-reload. |
275 | 304 | DATA_LAST_OPTIONS = "last_options" |
| 305 | +# The ServerVersionCoordinator instance backing the `update` platform entity |
| 306 | +# (issue #1760) — stored so the platform's async_setup_entry can retrieve it. |
| 307 | +DATA_UPDATE_COORDINATOR = "update_coordinator" |
| 308 | +# Set by async_maybe_auto_update right before it reloads the entry for an |
| 309 | +# automatic update ({"old": <version>}): the "server updated" notification must |
| 310 | +# only fire once the reloaded entry's bring-up actually installed and started |
| 311 | +# the new build — the reload call returns as soon as entry SETUP finishes, |
| 312 | +# while the pip install still runs in the background and can fail (review |
| 313 | +# finding on #1760). Bring-up pops it: notification on success, silent drop on |
| 314 | +# failure (the package/start repair issues cover that path). |
| 315 | +DATA_PENDING_UPDATE_NOTIFY = "pending_update_notify" |
276 | 316 |
|
277 | 317 | # Webhook auth modes (mirrors the webhook-proxy add-on's default posture). |
278 | 318 | WEBHOOK_AUTH_NONE = "none" # secret webhook URL is the shared secret (default) |
|
309 | 349 | # namespace (mirrors the webhook-proxy add-on's /api/mcp_proxy/oauth base). |
310 | 350 | OAUTH_BASE = "/api/ha_mcp_tools/oauth" |
311 | 351 |
|
| 352 | +# HACS "add repository" deep link for the custom component. Shared learn_more_url |
| 353 | +# for every repair issue that ends with "install/reinstall the component via |
| 354 | +# HACS" (the component-outdated issue and the legacy-HACS-source issue below). |
| 355 | +HACS_COMPONENT_URL = ( |
| 356 | + "https://my.home-assistant.io/redirect/hacs_repository/" |
| 357 | + "?owner=homeassistant-ai&repository=ha-mcp-integration&category=integration" |
| 358 | +) |
| 359 | + |
312 | 360 | # Repair-issue ids surfaced when server bring-up fails. |
313 | 361 | ISSUE_PACKAGE_FAILED = "server_package_install_failed" |
314 | 362 | ISSUE_START_FAILED = "server_start_failed" |
|
318 | 366 | # the server expects; this points the user at the HACS component update |
319 | 367 | # (non-blocking). |
320 | 368 | ISSUE_COMPONENT_OUTDATED = "component_outdated" |
| 369 | +# Repair issue surfaced when HACS is tracking the MAIN ha-mcp server repo for |
| 370 | +# this component (the pre-mirror install path — issue #1760). That install |
| 371 | +# keeps working (HACS downloads the repo snapshot at the release tag, which |
| 372 | +# contains the component), but HACS shows the SERVER's version numbers and |
| 373 | +# release notes, not the component's own; HACS has no repository-migration |
| 374 | +# mechanism, so this only self-resolves if the user re-adds the dedicated |
| 375 | +# mirror (homeassistant-ai/ha-mcp-integration). |
| 376 | +ISSUE_LEGACY_HACS_SOURCE = "legacy_hacs_source" |
0 commit comments