* Use websocket subscription for calendar events
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 <noreply@anthropic.com>
* Fix calendar events not loading on initial render
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 <noreply@anthropic.com>
* Fix calendar subscription data format mismatch
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.
* Address PR review comments
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 <noreply@anthropic.com>
* Extract event normalization to shared utility function
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 <noreply@anthropic.com>
* Address additional review comments
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 <noreply@anthropic.com>
* Update src/panels/lovelace/cards/hui-calendar-card.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update src/panels/lovelace/cards/hui-calendar-card.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update src/panels/calendar/ha-panel-calendar.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refactor fetchCalendarEvents to use shared normalization utility
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 <noreply@anthropic.com>
* Move date normalization into normalizeSubscriptionEventData
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 <noreply@anthropic.com>
* Replace any types with proper TypeScript types
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 <noreply@anthropic.com>
* Unify CalendarEventRestData and CalendarEventSubscriptionData
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 <noreply@anthropic.com>
* PR comments
* fix import
* fix import
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update eslint to v10.1.0
Migrate from eslint-plugin-import to eslint-plugin-import-x since the
original plugin uses removed ESLint 10 APIs (context.parserOptions,
context.parserPath). Airbnb-base non-import rules preserved via
FlatCompat with import rules stripped and replaced by import-x.
- eslint 9.39.4 → 10.1.0
- Add eslint-plugin-import-x 4.16.2
- Add @eslint/eslintrc and @eslint/js as explicit deps
- Remove --flag v10_config_lookup_from_file (now default)
- Replace /* eslint-env */ comment with config-based globals
- Update all import/ rule references to import-x/
* Remove unnecessary eslint-disable for generated gallery imports
The import-pages file is generated as .ts, so import-x/extensions
doesn't require an extension (ts: "never" in config).
* Cleaned up experience when no pin support is possible to provide better messaging.
* Improvements to messaging depending on lock features
* Added documentation links
* Added prettier format
* Add a summary for battery status and a battery strategy
* some cleanup around location given its a sub view and naming
* Use the device name rather than entity name
* Refactor into a maintenance panel
* Adjust naming
* rename
* Add maintenance dashboard to built in dashboard list
* use grey for maintenance colour
* Fix typos in maintenance panel
- _searchParms -> _searchParams
- Add Event type to _back parameter
- Fix duplicate closing tag
* Move maintenance strategy to src/panels/maintenance/strategies/
- Move maintenance-view-strategy.ts to maintenance panel directory
- Update import paths in get-strategy.ts, home-summaries.ts, and hui-home-summary-card.ts
- Fix ha-floor-icon import path in maintenance-view-strategy.ts
---------
Co-authored-by: Petar Petrov <MindFreeze@users.noreply.github.com>
* Add Last 365 Days option to energy date selection
There seem to be two use cases for the "Last 12 Months" option - those that expect it to produce whole months (original behaviour up to 2026.1, then again from 2026.4), and those that want an option for the last 365 days,
Given this descrepancy in expected behaviour, add an explicit "Last 365 days" option.
* Use subDays for last 365.
* Add loading state to energy dashboard
* Add fade-in/-out
* Update src/panels/lovelace/components/hui-energy-period-selector.ts
Co-authored-by: Tom Carpenter <T.Carpenter@leeds.ac.uk>
* Feedback
* Feedback
* Apply suggestion from @MindFreeze
---------
Co-authored-by: Tom Carpenter <T.Carpenter@leeds.ac.uk>
Co-authored-by: Petar Petrov <MindFreeze@users.noreply.github.com>
* Fix typos and syntax errors in ha-panel-climate.ts
- Rename _searchParms to _searchParams (typo fix)
- Fix duplicate closing hui-view-container tag
- Clean up formatting
* Fix duplicate hui-view-container closing tag in light and security panels