feat: add Home Screen widgets, SSE sitemap updates, and wide-display grid#1028
Open
timbms wants to merge 112 commits into
Open
feat: add Home Screen widgets, SSE sitemap updates, and wide-display grid#1028timbms wants to merge 112 commits into
timbms wants to merge 112 commits into
Conversation
Contributor
There was a problem hiding this comment.
Copilot reviewed 65 out of 68 changed files in this pull request and generated no comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 66 out of 69 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
timbms
force-pushed
the
feature/widgets-with-item-display
branch
from
January 29, 2026 07:41
4fd6b91 to
b576981
Compare
TAKeanice
force-pushed
the
openapigen-swiftui
branch
from
March 26, 2026 19:49
1f242b5 to
166a59c
Compare
Merged
timbms
force-pushed
the
feature/widgets-with-item-display
branch
5 times, most recently
from
May 28, 2026 09:24
35d5dea to
25cdb53
Compare
Adds a widget extension with switch and sensor widgets.
Switch widget:
- Available in small (1 item), medium (2 items), and large (4 items)
as separate widget registrations, so the configuration UI shows
exactly the right number of item slots for the selected size
- Interactive toggle with optimistic visual update on tap (Toggle with
custom PowerButtonToggleStyle, not Button)
- 600 ms pause in SetSwitchItemIntent.perform() prevents WidgetKit's
immediate timeline refresh from racing openHAB's async command
processing and overwriting the optimistic state flip
- State label ('ON'/'OFF') lives inside the ToggleStyle so it always
agrees with the button colour, never the lagging timeline entry
- Medium/large use a row layout (bold label + compact circle toggle)
with dividers; small shows a centred power button
- Previews and the widget gallery work without a configured home by
rendering a static non-interactive circle button
Sensor widget:
- Displays current state of Number/String items
Common infrastructure:
- Delete OpenHABWidgetLiveActivity.swift: importing ActivityKit without
Live Activity entitlements caused an EXC_GUARD/LIBXPC crash at
extension startup before any Swift code ran
- SwitchSmall/Medium/LargeConfigurationAppIntent with matching
SwitchSmall/Medium/LargeWidgetItemEntity types, each carrying an
@IntentParameterDependency on its own configuration intent for
home-filtered item selection in the picker
- openHAB icon overlay inset 14 pt from leading/top edge on all sizes
Signed-off-by: Tim Mueller-Seydlitz <timbms@gmail.com>
timbms
force-pushed
the
feature/widgets-with-item-display
branch
from
May 28, 2026 11:38
7cf0ab5 to
a092c56
Compare
…itor Port the two ItemEventStream improvements from feature/migration2SSE-minimal without pulling in the unrelated sitemap-polling changes: - Add networkMonitoringTask field: the network monitor now lives entirely inside the actor (started once via startMonitoringNetworkIfNeeded) instead of running an infinite for-await loop in the caller's task. startMonitoringNetwork() returns immediately after the first call. - Add 30-second alive watchdog: a background Task inside listen(using:) checks lastEventTime every 10 s and reconnects if no event (including ALIVE heartbeats) has been received for 30 s. This recovers silently dead connections that occur after a server restart without a TCP RST. Also fix WidgetItemMonitor.reloadWidgets(for:) which was still reloading the deleted 'OpenHABSwitchWidget' kind; update to the three separate kinds introduced when small/medium/large were split into separate widget structs. Signed-off-by: Tim Mueller-Seydlitz <timbms@gmail.com>
#1225) - Bump exact versions in BuildTools/Package.swift and update Package.resolved - Fix line_length violations newly flagged by SwiftLint 0.63.3: add disable comments in OpenHABSitemapWidgetEvent, OpenHABWidget, OpenHABImageProcessorTests, SitemapDiagnostics, and JSONParserTests - Remove now-superfluous closure_end_indentation disables in TextInputRowView and DatePickerInputRowView - SnapshotRowInputBuildResult: add explicit Sendable conformance (required by Task<Success: Sendable, …> in Swift 6) and guard it with // swiftformat:disable:next redundantSendable so the formatter leaves it intact Signed-off-by: Tim Mueller-Seydlitz <timbms@gmail.com>
- Add OpenHABShortcuts: AppShortcutsProvider registering all 10 intents with Siri/Shortcuts phrases for iOS 17+ - Add AppShortcuts.strings for all 9 supported locales (en/de/es/fi/fr/it/nb/nl/ru) using the .strings format required by the iOS 16 deployment target - Add resultValueName to GetItemStateIntent so its output is labeled in Shortcuts - Add ProvidesDialog to SetSwitchItemIntent and SetPlayerValueIntent - Simplify ItemEntity.displayRepresentation by removing the nonLocalizedDisplayString helper in favour of direct LocalizedStringResource string interpolation Signed-off-by: Tim Mueller-Seydlitz <timbms@gmail.com>
AppIntentsMetadataProcessor builds an NLP vocabulary model for Siri using each AppEnum case's DisplayRepresentation(title:synonyms:). Without synonyms the processor allocates synonym slots in its model but finds them empty, emitting 'unresolvable: empty template: Failed # variables.N.definitions.M.synomyms.K' warnings for every empty slot across all locales. Add 3 synonyms per case to SwitchAction, ContactState, and PlayerAction. This both fills the NLP model slots and improves Siri's recognition of different ways a user might name a switch action, contact state, or player command. Signed-off-by: Tim Mueller-Seydlitz <timbms@gmail.com>
The AppIntentsMetadataProcessor in Xcode 15+ expects App Shortcuts phrase localizations in String Catalog format (AppShortcuts.xcstrings). Using individual lproj/AppShortcuts.strings files causes the processor to fail to generate NLP synonym data for most locales, producing repeated 'unresolvable: empty template: Failed # variables.N.definitions.M.synomyms.K' build warnings. Consolidate all 9 locale translations (de, en, es, fi, fr, it, nb, nl, ru) into a single AppShortcuts.xcstrings String Catalog and remove the individual .strings files. Signed-off-by: Tim Mueller-Seydlitz <timbms@gmail.com>
AppShortcuts.xcstrings requires iOS 17.0+. Xcode set the minimum to 17.6 (latest iOS 17.x in the SDK) and watchOS to 10.6 accordingly. Also includes Xcode-generated Localizable.xcstrings additions from AppEnum caseDisplayRepresentations synonyms (extracted automatically from d917708), and extractionState markers on secondary phrases in multi-phrase App Shortcuts (Xcode extraction limitation, runtime behaviour unchanged). Signed-off-by: Tim Mueller-Seydlitz <timbms@gmail.com>
- OpenHABItemCache: add blank line after #endif (SwiftLint) - Localizable.xcstrings: fill in missing translations for AppIntents string keys that were in 'new' state (SSE/AppIntents warnings) Signed-off-by: Tim Mueller-Seydlitz <timbms@gmail.com>
…ete translations - Rename OpenHABIconOverlay.swift → OpenHABIconWatermark.swift to better reflect its purpose as a watermark overlay on widget preview images - Complete missing translations in Localizable.xcstrings for all supported languages, resolving all NEW-state entries Signed-off-by: Tim Mueller-Seydlitz <timbms@gmail.com>
…play Merges CarPlay SSE streaming support and sitemap-based favorites scene. Localizable.xcstrings resolved by preserving HEAD's multi-language translations while adding carplay-sse's auto-generated comments and new CarPlay-specific keys. Signed-off-by: Tim Mueller-Seydlitz <timbms@gmail.com>
- '%@ • %@': add de/es/fi/fr/it/nb/nl/ru (format string, identical to en) - 'Number Item': add es/fi/nb/ru translations - Local Network alert message: add es/fi/nb/ru translations Signed-off-by: Tim Mueller-Seydlitz <timbms@gmail.com>
Signed-off-by: openhab-bot <info@openhabfoundation.org>
Three bugs fixed: 1. sitemapChanged and widget-notFound called startStreaming(), which cancelled and rebuilt the entire SSE stack (NetworkTracker reset + new subscription). The onTermination handler on the old continuation could fire while the new task was still doing network round-trips, causing SitemapEventStream.cleanupContinuation to cancel listenTask and create a gap in event coverage. Replace with schedulePageRefresh(), which re-fetches only the page without touching the SSE stream. 2. No page refresh on SSE reconnect: if SITEMAP_CHANGED was missed during a disconnect the page stayed permanently stale. Add a needsRefreshOnReconnect flag (matching SitemapPageViewModel) that triggers schedulePageRefresh() on the next .connected event. 3. Calling NetworkTracker.shared.startTracking() on every restart (sitemapChanged, notFound) could reset the shared tracker's active connection and briefly break the main app's SSE. Now startTracking is only called on initial connect or sitemap-selection change. currentPage and currentService are now stored properties so handleSseMessage and refreshPage can read them without being threaded through every function parameter. Signed-off-by: Tim Mueller-Seydlitz <timbms@gmail.com>
timbms
force-pushed
the
feature/widgets-with-item-display
branch
from
July 12, 2026 15:13
6983abb to
7d57f63
Compare
Signed-off-by: DigiH <17110652+DigiH@users.noreply.github.com>
…ity alerts ImageRowView: show an inline error card (icon + HTTP status message) when a linked image fails to load instead of leaving a blank area. Clears on URL change or successful reload. SitemapPageView: exclude SitemapPageError (noActiveConnection, serviceUnavailable, noData) from the modal alert — these are transient connectivity states already reflected by the offline/loading indicators and should not block the user. Signed-off-by: Tim Mueller-Seydlitz <timbms@gmail.com>
…th-item-display Signed-off-by: Tim Mueller-Seydlitz <timbms@gmail.com>
Signed-off-by: openhab-bot <info@openhabfoundation.org>
Signed-off-by: DigiH <17110652+DigiH@users.noreply.github.com>
Signed-off-by: Tim Mueller-Seydlitz <timbms@gmail.com>
…ts (#1298) Signed-off-by: DigiH <17110652+DigiH@users.noreply.github.com>
Signed-off-by: openhab-bot <info@openhabfoundation.org>
…th-item-display Signed-off-by: Tim Mueller-Seydlitz <timbms@gmail.com>
Signed-off-by: DigiH <17110652+DigiH@users.noreply.github.com>
CPGridButton only supports a single text line, causing the setup instruction to be clipped on all display sizes and in all languages. Switch to CPInformationTemplate which renders the full text without truncation. Signed-off-by: Tim Mueller-Seydlitz <timbms@gmail.com>
- Add parentWidgetId to OpenHABWidget via ObjC associated object (no stored-property layout change) and propagate it in flatten(_:); this was required for frame-child visibility tracking without corrupting Combine's @published field scan under concurrent test execution. - Extract visibility logic into sitemapVisibleWidgets(_:) so both SitemapPageViewModel.relevantWidgets and the tests call the same code path instead of a duplicated helper. - Fix frame visibility: empty frames (no children) are now hidden to match Android parity; previously only frames with children where all were invisible were hidden. - Fix #expect crash in PreviewWidgetFactoryTests: extract non-Sendable OpenHABWidget properties to local Sendable variables before #expect to avoid null-function-pointer crash from -enable-actor-data-race-checks. - Fix redundant try #require on already-unwrapped UIColor in NumberStateTests. - Add emptyFrameIsHidden test. - Remove stale FlexColorPicker pin from Package.resolved. Signed-off-by: Tim Mueller-Seydlitz <timbms@gmail.com>
Signed-off-by: openhab-bot <info@openhabfoundation.org>
…uttons - Drop .button and .selection from CarPlay compatibility; neither type appears at page level in practice. - Remove pushMappingList and segmented-switch handling; mapping lists are not a good fit for the CarPlay grid interaction model. - Add press-release support: plain switch toggles ON/OFF; a switch with a single mapping carrying hasPressReleaseBehavior sends the press command, sleeps 500 ms, then sends the release command; a switch with widget-level releaseCommand is handled the same way. - Exclude itemless Switch widgets (used as sitemap frames/containers) from the CarPlay grid via a widget.item != nil guard. Signed-off-by: Tim Mueller-Seydlitz <timbms@gmail.com>
Signed-off-by: openhab-bot <info@openhabfoundation.org>
Signed-off-by: DigiH <17110652+DigiH@users.noreply.github.com>
Signed-off-by: DigiH <17110652+DigiH@users.noreply.github.com>
Signed-off-by: openhab-bot <info@openhabfoundation.org>
Signed-off-by: DigiH <17110652+DigiH@users.noreply.github.com>
Adds translations for "None" and "Sitemap for CarPlay" picker labels, and updates carplay_not_configured / carplay_not_configured_detail to match the current English text (Switch items, iOS app settings) across de, es, fi, fr, it, nb, nl, and ru. Signed-off-by: Tim Mueller-Seydlitz <timbms@gmail.com>
Signed-off-by: openhab-bot <info@openhabfoundation.org>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
Four features landing together:
CPGridTemplatewith openHAB SF symbol iconsRaises minimum deployment targets to iOS 18 / watchOS 11 / macOS 15 (required for interactive widget APIs and
AsyncSequence.Failure/ SE-0421).Widget extension (
openHABWidget)Switch widgets
Three sizes backed by separate
WidgetConfigurationIntents:SwitchSmallConfigurationAppIntentSwitchMediumConfigurationAppIntentSwitchLargeConfigurationAppIntentEach widget lets the user select a Home and then one or more Switch items. Tapping a switch sends the toggle command via
SetSwitchItemIntent.Sensor widget
Displays the current state of a Number or String item (e.g. temperature, humidity). Available in small and medium sizes. Refreshes every 5 minutes; also updated live via SSE.
Real-time widget updates
WidgetItemRegistry(new,OpenHABCore) — actor that tracks which items have active widgets using App Group UserDefaults (group.org.openhab.app), shared between the widget extension and the main app without IPC.WidgetItemMonitor(new, main app) — started fromAppDelegateon launch. Subscribes toItemEventStreamSSE events and callsWidgetCenter.shared.reloadTimelines(ofKind:)for all widget kinds when a tracked item's state changes. Stale registry entries are cleaned up each time the app becomes active.Sitemap SSE migration
Network savings — measured with Proxyman over a ~30 s session with periodic state changes:
Per state change, each long-poll round-trip returns ~38 KB of full page JSON; a typical SSE widget event is 100–300 bytes — roughly 100–300× smaller.
SitemapEventStream(new,OpenHABCore) — actor-isolated SSE connection manager: subscribes to the server's sitemap event endpoint, broadcastsSitemapEventMessagevalues (.alive,.sitemapChanged,.widget), reconnects with exponential backoff, and includes a 30 s watchdog to detect silently dead connections.OpenAPIServiceProtocol— addsopenHABSitemapWidgetEvents(returningany AsyncSequence<SitemapEventMessage, any Error> & Sendable) andopenHABEvents. SSE event parsing and 404 →SitemapSseError.unsupportedmapping are encapsulated insideOpenAPIService.SitemapPageViewModel— after initial fetch, checksshouldUseSSE(); if true, hands off tostartSSEand returns from the polling loop.applySseWidgetEventapplies widget delta events in-place viaOpenHABWidget.apply(event:); falls back to full page reload when a widget is not found or its description changed.startLongPollingFallbacksetsssePreferred = falseand restarts polling.OpenHABWidget.apply(event:)(new,OpenHABCore) — recursive in-place widget update from anOpenHABSitemapWidgetEvent. Returns.applied,.notFound, or.requiresPageReload.Wide-display sitemap grid
On iPad (and any wide horizontal size class), sitemap pages now use a two-column adaptive grid via
SitemapGridLayout. Media widgets — image, video, chart, webview, and map — are classified as full-width cells and span both columns, matching BasicUI.SitemapGridLayout(new) — groupsSitemapRowInputitems into sections and row groups; classifies cells as half-width or full-width based on widget type.SitemapPresentationPolicy(new) — decides between list and grid presentation based on horizontal size class; drivesSitemapPageViewlayout switching.EmbeddingRowInputView— media rows now use standardregularInsets(16 pt leading/trailing) instead of zero-inset edge-to-edge bleed.Image rows —
KFImage(static images, charts) getsframe(maxWidth: .infinity)so landscape images fill the available width.KFAnimatedImage(GIFs) usesAnimatedGIFFrameModifierwhich computes an exact frame from the GIF's natural aspect ratio viaonGeometryChange(noGeometryReader).Video rows — fixed
frame(height: 200)removed; height is now driven byaspectRatio(contentMode: .fit)+frame(maxWidth: .infinity).CarPlay support
CarPlay presents a sitemap-based favorites scene configurable in Settings → CarPlay.
CarPlaySceneDelegate(new) — manages theCPTemplateApplicationSceneDelegatelifecycle. On connect, loads the configured sitemap and renders it as aCPGridTemplatewith openHAB SF symbol icons (mapped from openHAB icon names). Subscribes toSitemapEventStreamSSE events and applies widget updates in real time; reconnects on network change or watchdog timeout.PreferencesascarPlaySitemapNameCPListTemplatewhen no compatible sitemap widgets are found or CarPlay is not yet configuredcom.apple.developer.carplay-maps(viaopenHAB-CarPlay.entitlements)ItemEventStreamimprovementsstartMonitoringNetworkIfNeededkeeps the network-change loop alive for the actor's lifetime;startMonitoringNetworknow returns immediately instead of blockingiOS 17 clean-up
Removes the
#available(iOS 17)guard and the hand-rolledNWPathMonitor.paths()compatibility shim fromNWPathMonitoring.swiftnow that iOS 16 is no longer supported.Test plan
Widgets
Sitemap SSE
Wide-display grid
CarPlay