-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Use websocket subscription for calendar events #27906
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Conversation
Replace polling-based calendar event fetching with real-time websocket subscriptions. This leverages the new subscription API added in core to provide automatic updates when calendar events change, eliminating the need for periodic polling. The subscription pattern follows the same approach used for todo items, with proper lifecycle management and cleanup. Related: home-assistant/core#156340 Related: #27565 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Remove premature subscription attempt in setConfig() that was failing because the date range wasn't available yet. The subscription now properly happens when the view-changed event fires from ha-full-calendar after initial render, which includes the necessary start/end dates. This ensures calendar events load immediately when the component is first displayed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
The websocket subscription returns event data with fields named start and end, but the frontend was expecting dtstart and dtend. This caused events to not display because the data wasn't being properly mapped. Now properly transform the subscription response format: - Subscription format: start/end/summary/description - Internal format: dtstart/dtend/summary/description This ensures both initial event loading and real-time updates work correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR converts calendar event fetching from REST API calls to WebSocket subscriptions, enabling real-time updates for calendar events. The change affects both the calendar card (Lovelace) and the calendar panel, implementing a subscription-based pattern that allows the UI to receive live updates when calendar events change.
Key changes:
- Replaced
fetchCalendarEventswithsubscribeCalendarEventsusing WebSocket subscriptions - Added subscription management with proper cleanup in
disconnectedCallback - Implemented per-calendar subscription tracking to handle individual calendar selection/deselection
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 11 comments.
| File | Description |
|---|---|
| src/data/calendar.ts | Adds new CalendarEventSubscription interface and subscribeCalendarEvents function for WebSocket-based event subscriptions |
| src/panels/lovelace/cards/hui-calendar-card.ts | Converts calendar card from REST API fetching to WebSocket subscriptions with subscription lifecycle management |
| src/panels/calendar/ha-panel-calendar.ts | Converts calendar panel from REST API fetching to WebSocket subscriptions with per-calendar subscription management |
Fixes based on Copilot review feedback: 1. **Fixed race conditions**: Made _unsubscribeAll() async and await it before creating new subscriptions to prevent old subscription events from updating UI after new subscriptions are created. 2. **Added error handling**: All unsubscribe operations now catch errors to handle cases where subscriptions may have already been closed. 3. **Fixed type safety**: Replaced 'any' type with proper CalendarEventSubscriptionData type and added interface definition for subscription response data structure. 4. **Improved error tracking**: Calendar card now accumulates errors from multiple calendars instead of only showing the last error. 5. **Prevented duplicate subscriptions**: Added checks to unsubscribe existing subscriptions before creating new ones in both _subscribeCalendarEvents and _requestSelected. 6. **Fixed null handling**: Properly convert null values to undefined for CalendarEventData fields to match expected types. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Reduced code duplication by extracting the calendar event normalization logic from both hui-calendar-card.ts and ha-panel-calendar.ts into a shared utility function in calendar.ts. The normalizeSubscriptionEventData() function handles the conversion from subscription format (start/end) to internal format (dtstart/dtend) in a single, reusable location. This improves maintainability by ensuring consistent event normalization across all calendar components and reduces the risk of divergence. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
There was a problem hiding this 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 3 out of 3 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (1)
src/data/calendar.ts:1
- The
locationfield fromCalendarEventSubscriptionDatais normalized but not included in the returnedCalendarEventobject. This appears to be a data loss issue - eitherlocationshould be added toCalendarEventDatainterface and included innormalizedEventData, or it should be removed fromCalendarEventSubscriptionDataif not supported.
import { getColorByIndex } from "../common/color/colors";
Fixed remaining issues from code review: 1. **Added @State decorator to _errorCalendars**: Ensures proper reactivity in calendar card when errors occur or are cleared, triggering UI updates. 2. **Fixed error accumulation in panel calendar**: Panel now properly accumulates errors from multiple calendars similar to the card implementation, preventing previously failed calendars from being hidden when new errors occur. 3. **Removed duplicate subscription check**: Deleted redundant duplicate subscription prevention in _requestSelected() since _subscribeCalendarEvents() already handles this at lines 221-227. Note: The [nitpick] comment about loading states during await is a performance enhancement suggestion, not a required fix. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
There was a problem hiding this 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 3 out of 3 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (1)
src/data/calendar.ts:1
- The
locationfield inCalendarEventSubscriptionDatais not used in thenormalizeSubscriptionEventDatafunction. This should be documented in the interface or handled in the normalization function, as calendar events typically support location information.
import { getColorByIndex } from "../common/color/colors";
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
Eliminated code duplication by reusing normalizeSubscriptionEventData() in fetchCalendarEvents(). After extracting date strings from the REST API response format, we now convert to a subscription-like format and pass it to the shared utility. This ensures consistent event normalization across both REST API and WebSocket subscription code paths, reducing maintenance burden and potential for divergence. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
The getCalendarDate helper is part of the normalization process and should be inside the normalization function. This makes normalizeSubscriptionEventData handle both REST API format (with dateTime/date objects) and subscription format (plain strings). Changes: - Moved getCalendarDate into normalizeSubscriptionEventData - Updated CalendarEventSubscriptionData to accept string | any for start/end - Made normalizeSubscriptionEventData return CalendarEvent | null for invalid dates - Simplified fetchCalendarEvents to use the shared normalization - Added null filtering in calendar card and panel event handlers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Added proper types for calendar event data:
- CalendarDateValue: Union type for date values (string | {dateTime} | {date})
- CalendarEventRestData: Interface for REST API event responses
- Updated fetchCalendarEvents to use CalendarEventRestData[]
- Updated CalendarEventSubscriptionData to use CalendarDateValue
- Updated getCalendarDate to use proper type guards with 'in' operator
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
Both interfaces had identical structures, so unified them into a single CalendarEventSubscriptionData interface that is used for both REST API responses and WebSocket subscription data. Changes: - Removed CalendarEventRestData interface - Updated fetchCalendarEvents to use CalendarEventSubscriptionData - Added documentation clarifying the interface is used for both APIs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
src/data/calendar.ts
Outdated
| * Calendar event data from both REST API and WebSocket subscription. | ||
| * Both APIs use the same data format. | ||
| */ | ||
| export interface CalendarEventSubscriptionData { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why call it SubscriptionData if it is used in the REST API too? Just rename it to CalendarEventData?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, thats used for the normalized version...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed it to CalendarEventApiData 🤷
Proposed change
Prompted from #27565
Type of change
Example configuration
Additional information
Checklist
If user exposed functionality or configuration variables are added/changed: