Skip to content

Add iOS Live Activity webhook handlers to mobile_app#166072

Draft
rwarner wants to merge 33 commits intohome-assistant:devfrom
rwarner:feat/ios-live-activity
Draft

Add iOS Live Activity webhook handlers to mobile_app#166072
rwarner wants to merge 33 commits intohome-assistant:devfrom
rwarner:feat/ios-live-activity

Conversation

@rwarner
Copy link
Copy Markdown

@rwarner rwarner commented Mar 20, 2026

Proposed change

Adds server-side support for iOS Live Activities in the mobile_app integration. This is the HA core companion to the iOS companion app PR (home-assistant/iOS#4444) and the relay server PR (home-assistant/mobile-apps-fcm-push#278).

Live Activities let Home Assistant automations push real-time state to the iOS Lock Screen. The iOS companion app handles the ActivityKit lifecycle; this PR adds the webhook handlers and notification routing that HA core needs to store, manage, and deliver per-activity push tokens.

How it works: When a notification contains live_update: true and a tag, the notify service includes the stored APNs Live Activity token alongside the normal FCM registration token in the same request to the relay server. The relay server places it in the FCM message's apns.liveActivityToken field, and FCM handles APNs delivery automatically — no separate endpoint, no APNs credentials, no environment routing needed.

What this adds:

  • Explicit SCHEMA_APP_DATA validation for supports_live_activities, supports_live_activities_frequent_updates, live_activity_push_to_start_token, and live_activity_push_to_start_apns_environment fields in device registration (push-to-start token and environment are vol.Inclusive — must be provided together)
  • update_live_activity_token webhook — stores per-activity APNs push tokens reported by the iOS app when a Live Activity is created locally via ActivityKit
  • live_activity_dismissed webhook — cleans up stored tokens when a Live Activity ends on the device (also cleaned up on config entry unload)
  • Both handlers fire bus events (mobile_app_live_activity_token_updated / mobile_app_live_activity_dismissed) with EventOrigin.remote so automations can react to activity lifecycle
  • notify.py routing — when a notification contains live_update: true and a tag, includes the Live Activity APNs token as live_activity_token alongside the FCM push_token to the same relay URL. Falls back to the push-to-start token (iOS 17.2+) if no per-activity token exists for that tag
  • supports_live_activities() utility helper in util.py
  • In-memory DATA_LIVE_ACTIVITY_TOKENS store initialized in __init__.py
  • 8 new tests (4 webhook handler tests, 4 notification routing tests)

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New integration (thank you!)
  • New feature (which adds functionality to an existing integration)
  • Deprecation (breaking change to happen in the future)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Additional information

@home-assistant
Copy link
Copy Markdown

Hey there @home-assistant/core, mind taking a look at this pull request as it has been labeled with an integration (mobile_app) you are listed as a code owner for? Thanks!

Code owner commands

Code owners of mobile_app can trigger bot actions by commenting:

  • @home-assistant close Closes the pull request.
  • @home-assistant rename Awesome new title Renames the pull request.
  • @home-assistant reopen Reopen the pull request.
  • @home-assistant unassign mobile_app Removes the current integration label and assignees on the pull request, add the integration domain after the command.
  • @home-assistant add-label needs-more-information Add a label (needs-more-information, problem in dependency, problem in custom component, problem in config, problem in device, feature-request) to the pull request.
  • @home-assistant remove-label needs-more-information Remove a label (needs-more-information, problem in dependency, problem in custom component, problem in config, problem in device, feature-request) on the pull request.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Home Assistant Core support in the mobile_app integration for iOS Live Activities by introducing webhook handlers that store and clear per-activity APNs push tokens and emit lifecycle events for automations.

Changes:

  • Extend SCHEMA_APP_DATA and constants to support Live Activities capability flags and push-to-start registration fields.
  • Add update_live_activity_token and live_activity_dismissed webhooks that manage an in-memory token store and fire remote-origin bus events.
  • Add a supports_live_activities() helper and webhook tests covering token storage, defaults, and cleanup.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
homeassistant/components/mobile_app/const.py Adds Live Activity-related constants/events and extends registration SCHEMA_APP_DATA.
homeassistant/components/mobile_app/__init__.py Initializes a new in-memory DATA_LIVE_ACTIVITY_TOKENS store under hass.data[DOMAIN].
homeassistant/components/mobile_app/webhook.py Implements the new Live Activity webhook handlers and fires lifecycle events.
homeassistant/components/mobile_app/util.py Adds supports_live_activities() helper based on stored app_data.
tests/components/mobile_app/test_webhook.py Adds tests for storing tokens, default env behavior, and dismiss cleanup/event firing.
Comments suppressed due to low confidence (1)

tests/components/mobile_app/test_webhook.py:1398

  • This test only asserts the HTTP status. To fully validate the contract of live_activity_dismissed (which returns empty_okay_response()), also assert the JSON body is {} (and optionally that no tokens were removed when none existed) to prevent regressions in response shape/side effects.
    resp = await webhook_client.post(
        f"/api/webhook/{webhook_id}",
        json={
            "type": "live_activity_dismissed",
            "data": {
                "tag": "nonexistent_activity",
            },
        },
    )

    assert resp.status == HTTPStatus.OK

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Copilot AI review requested due to automatic review settings March 23, 2026 13:03
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Copilot AI review requested due to automatic review settings March 23, 2026 18:29
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Copilot AI review requested due to automatic review settings March 23, 2026 19:55
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Copilot AI review requested due to automatic review settings March 24, 2026 14:09
Copilot AI review requested due to automatic review settings March 25, 2026 19:09
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Copilot AI review requested due to automatic review settings March 26, 2026 13:10
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

rwarner and others added 2 commits March 26, 2026 09:55
…ivities

Unifies the iOS and Android notification data field: live_update: true now
triggers Live Activity routing on iOS, matching the field Android already uses.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 26, 2026 14:27
@bgoncal
Copy link
Copy Markdown
Member

bgoncal commented Apr 1, 2026

@rwarner the PR in the iOS repo is almost ready to merge, just minor touches, if you think this PR (in Core) is ready, please mark it as ready for review

Copy link
Copy Markdown
Member

@edenhaus edenhaus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A fast initial review


device: dr.DeviceEntry = hass.data[DOMAIN][DATA_DEVICES][webhook_id]
hass.bus.async_fire(
EVENT_LIVE_ACTIVITY_DISMISSED,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's confusing that it's called sometimes live_update and then live_activity

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From home-assistant/iOS#4444 (comment) it looks like we should rename everything to live_update

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The user-facing notification flag is live_update: true throughout. The live_activity naming is intentionally kept for the ActivityKit-specific internals (token store, push-to-start registration, webhook names) where it refers to the Apple feature rather than the notification field.

It does get a bit difficult, but don't want to overstep with Android references and/or YAML references to live_update

rwarner and others added 3 commits April 1, 2026 16:24
…y _get_live_activity_token signature

- Drop EVENT_LIVE_ACTIVITY_TOKEN_UPDATED and EVENT_LIVE_ACTIVITY_DISMISSED — nothing
  consumes these events in any of the three repos (no automation triggers, no iOS
  listener, no relay usage), so they add noise without value
- Remove supports_live_activities() from util.py — defined but never called
- Pass app_data directly into _get_live_activity_token instead of the full
  registration dict (edenhaus review feedback)
- Group Live Activity push constants with other PUSH attrs in const.py
- Update tests to remove event-capture assertions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The generic 'tag' field name collides with the notification tag used
elsewhere in mobile_app. Using 'live_activity_tag' makes the webhook
contract unambiguous. notify.py continues to read 'tag' from the
notification payload (user YAML) unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Core registered 'update_live_activity_token' and 'live_activity_dismissed'
but the iOS app sends 'mobile_app_live_activity_token' and
'mobile_app_live_activity_dismissed', matching the mobile_app_ prefix
convention used elsewhere in the integration. Rename core handlers to match.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@rwarner
Copy link
Copy Markdown
Author

rwarner commented Apr 1, 2026

Resolved and fixed comments. Difficult naming scheme between live_activity and live_update especially considering Android references, iOS references, and YAML references. Open to suggestions though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants