Starting in iOS 15, there's a number of crashes happening in the background with Realm. They don't appear to be due to the file lock in the shared app container, but this may help resolve them either way -- easy to see if the next beta doesn't crash a bunch.
## Summary
Fixes unnecessarily doing a sensor update pass when launching in the background, as well as an occasional crash talking to UIApplication's applicationState off the main thread.
## Screenshots
<!-- If this is a user-facing change not in the frontend, please include screenshots in light and dark mode. -->
## Link to pull request in Documentation repository
<!-- Pull requests that add, change or remove functionality must have a corresponding pull request in the Companion App Documentation repository (https://github.com/home-assistant/companion.home-assistant). Please add the number of this pull request after the "#" -->
Documentation: home-assistant/companion.home-assistant#
## Any other notes
<!-- If there is any other information of note, like if this Pull Request is part of a bigger change, please include it here. -->
## Summary
Fires a sensor update pass if the app is running when the focus status changes.
## Any other notes
The focus sensor _always_ live-updates, but it does so in the Intents extension. This allows the Intents extension to inform the app that it did an update, which (unfortunately, for now) fires a sensor update pass in the app. So we're over-updating the sensors, but we're keeping the in-app sensor list updated. Worth the cost, I think, since the app running when focus changes happening feels rare unless the user's playing with the sensor.
## Summary
- Upgrades the font, config, and adds a migration for renamed/removed icons.
- Migrates the one use of a renamed/removed one: `laptop-mac` -> `laptop`
## Any other notes
This change should also make it a little easier to do the migrations, since the Realm+Initialization part won't need to be touched, probably.
## Summary
Fixes the insta-updating of the focus sensor on iOS 15.
## Any other notes
`INFocusStatusCenter.default.focusStatus` always returns isFocused=false in the extension, but the intent provides the correct focus status for each update -- so we need to cache this value in the extension, and not trust the focus center state.
## Summary
Fixes a crash caused by infinitely recursing the value change.
## Any other notes
This also allows setting fractional minute values, every 15 seconds. The minimum timer which we check is 5 seconds, and that low means we won't detect changes if they occur in a 10 second period which feels too low.
Refs #945. This will not be available until we switch to compiling builds with Xcode 13, regardless of when it is merged.
## Summary
Adds a "Focus" binary sensor which is on when focus is enabled. This updates live, even when the app isn't running, via Intents.
## Link to pull request in Documentation repository
Documentation: home-assistant/companion.home-assistant#543
## Any other notes
Followup is needed for onboarding to prompt for this permission.
Fixes regression in #1487.
## Summary
Ephemeral webhook sends do not have any persisted info on them, and that's to be expected.
## Any other notes
None.
Fixes#1473. Again.
## Summary
When we issue webhook requests, we were failing to cancel any previous requests (which want to be cancelled) that were executed on not-the-background session. This moves to now checking both the background and non-background for cancellable requests.
## Any other notes
- Moves to explicitly cancelling, rather than silently replacing and succeeding, replaced requests. For example, a sensor update will now be explicitly cancelled if a new sensor update comes through, rather than following the success path.
- This resolves an issue where a sensor update occurs, fails on the non-background session, and retries with the same request data on the background session. This can lead to an older sensor update request, with outdated information, happening long after the most recent and correct one finishing.
Fixes#1473.
Refs #1460/#1467.
## Summary
When an earlier request gets applied later than we expect, we also need to assume it has replaced values similar to the transient update case fixed before.
## Any other notes
I am going to keep telling myself that the long-term benefit of the sensor caching outweighs having to figure out all of these real-world edge cases the hard way. In this case, I already expected it, I just did not fully think through the ramifications of the edge case and how it would look from the server perspective.
Fixes#1460.
## Summary
Fixes our internal cache being out of sync with the sensor values on the server.
## Any other notes
This issue occurs when, for example, we transition from value1 -> value2 -> value1. If the value2 update fails from our perspective, but successfully hits the server, we may not realize that we need to send value1 up again in the future.
Adds new fastlane lanes:
- `fastlane lint` which checks the linters
- `fastlane autocorrect` which applies the linters which can autocorrect (Rubocop, SwiftFormat)
Adds a build step to the Codegen abstract target which runs SwiftFormat in lint mode, pointing out what it's going to change when run.
Applies SwiftFormat to nearly all code -- exempts a few externally-sourced files and generated code.
## Summary
Maybe fixes a few crashes happening on watchOS that look like the iOS 14-era background crashes around file locks.
## Any other notes
I'm pretty sure Realm is working around the watchOS crashes by doing some kind of different file lock, so it's possible that we're entering the background and being killed for being in a write at the same time. All of these crashes have the infamous 0xdead10cc code.
This may address crashes which look like:
```
Exception Type: EXC_CRASH (SIGKILL)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
Termination Reason: Namespace RUNNINGBOARD, Code 0xdead10cc
Triggered by Thread: 0
```
As well as ones that are crashing deep in Realm during a write:
```
Exception Type: EXC_CRASH (SIGKILL)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
Termination Reason: Namespace RUNNINGBOARD, Code 0xdead10cc
Triggered by Thread: 0
Thread 0 name:
Thread 0 Crashed:
0 libsystem_kernel.dylib 0x21431508 mkfifo + 8
1 Realm 0x055d17d0 realm::util::File::lock+ 3217360 (bool, bool) + 476
2 Realm 0x0542f51c _hidden#8599_ + 76
3 Realm 0x0543094c realm::DB::get_number_of_versions+ 1509708 () + 32
4 Realm 0x05775260 _hidden#13450_ + 116
5 Realm 0x05774ea4 realm::Realm::begin_transaction+ 4935332 () + 64
6 Realm 0x053603d8 _hidden#6536_ + 656344 (__hidden#6695_:0)
7 RealmSwift 0x05a5b5a4 Realm.write<A>(withoutNotifying:_:) + 275876 (__hidden#4565_:0)
8 Shared 0x05cbfda4 closure #4 in WebhookResponseUpdateComplications.handle(request:result:) + 252 (WebhookResponseUpdateComplications.swift:69)
…
```
among many, many others. Only on watchOS 7. I'm not sure why this has begun crashing in the betas; perhaps updating Realm is causing new code paths, or more likely we're doing something slightly different timing-wise.
- Reverts #1418 - there's enough logic that is relying on the single-threadedness of then/map-ing on a shared queue.
- Forces all `Current.api` access to be done not on a queue intentionally, to avoid thread jumping when we don't expect, which is the core crash that this was trying to fix.
Adds code coverage reports to pull requests. Enabling code coverage gathering appears to be about a 25% increase in build time, unfortunately, so just enabling it for the App/Shared targets and doing it in a separate scheme so it doesn't impact local build times.
Fixes#1398.
## Summary
There's a core bug somewhere that's causing webhooks to start 5xx-ing. I haven't been able to reproduce it locally yet. Adding this log should help users who run into this bug, since we don't otherwise share these network failures for webhooks.
## Screenshots
(Pretend like 200 is really a failure here.)

Fixes#1397.
## Summary
Makes server version optional, returning nil when we don't know rather than a fallback version.
## Screenshots
n/a
## Link to pull request in Documentation repository
n/a
## Any other notes
Prevents an issue where we'd alert about the fallback version being old enough to have an alert, rather than the actual version which comes later. Amusingly the work I did to make sure that we'd handle app-launch-to-web-view events supporting an onboarding flow in the middle causes the alerts to be delayed until the webview loads after initial login.
Replace #1013.
## Summary
Keeps track of what sensors we've sent up during the session and only pushes up changes.
## Screenshots
Just tabbing around between apps on Mac:
```
14:49:15.876 [Info] [main] [HAAPI.swift:824] UpdateSensors(trigger:location:) > updating sensors ["frontmost_app"]
14:49:16.561 [Info] [main] [HAAPI.swift:824] UpdateSensors(trigger:location:) > updating sensors ["frontmost_app"]
14:49:17.422 [Info] [main] [HAAPI.swift:824] UpdateSensors(trigger:location:) > updating sensors ["frontmost_app"]
14:49:30.550 [Info] [main] [HAAPI.swift:824] UpdateSensors(trigger:location:) > updating sensors ["frontmost_app"]
14:49:32.363 [Info] [main] [HAAPI.swift:824] UpdateSensors(trigger:location:) > updating sensors ["frontmost_app"]
```
## Link to pull request in Documentation repository
No user-facing changes.
## Any other notes
Unlike #1013, this does not persist the sensor values to disk. This is a place that can be improved, but there are some unanswered questions/complications with storing to disk (especially around migrations and cleaning up the values when upgrading and when hardware devices change and wrong values are shown) that could probably be solved a little cleaner in the future transparently to consumers of these types.
## Summary
Instead of saying something like `Shared.WebhookError code 1` when the webhook is responding back with status code 503, gives a more appropriate error.
## Any other notes
What's really fun is the order of the enum appears to not matter for the debug error code. Reading the enum, you might think status code 1 was the 2nd error in the Error enum, but it's actually the 4th error in the list.
## Summary
- Fixes a crash when saving complications due to #1360 trying to save the MaterialDesignIcons model object as a String.
- Fixes complications not updating on save on the Watch if there are no template-requiring complications.
- Fixes firing the 'success' state on actions on the Watch immediately after asking the phone to send the request, rather than when it completes. This will make it feel slower but will be more accurate since it's failable.
- Updates Communicator to 4.x (the latest) and adjust to its changes.
## Screenshots
n/a
## Link to pull request in Documentation repository
n/a
## Any other notes
As Communicator keeps diverging from how the WatchConnectivity API structures things (especially around error handling) it may be worth thinking about going back to using it directly. For now though keeping our dependencies up-to-date is more important than inaction.
Fixes#1300.
## Summary
Updates Alamofire to 5.x and updates how we do authentication adapting and failure retrying.
## Screenshots
n/a
## Link to pull request in Documentation repository
n/a
## Any other notes
- Switches to using `AuthenticationInterceptor` to handle authenticated requests. This has a lot of good things: it's heavily tested, it only executes the refresh one at a time, and it has explicit handling of "this request failed with an _old_ access token" which is the root cause of some logouts in #1300.
- Switches from manually doing retries and backoffs to using `RetryPolicy` which also adds in retries for 5xx errors in addition to all of the URLError-specific logic that it has.
- Updates the apparently-copied-from-`AlamofireObjectMapper` repository for 5.x and removes some old Sodium-based handling that is now part of the Webhook flow, which is separate from Alamofire.
Fixes#977.
## Summary
Adds a sensor for the current frontmost app, also known as the current foreground or active app.
## Link to pull request in Documentation repository
Documentation: home-assistant/companion.home-assistant#425
## Any other notes
Creates `sensor.frontmost_app` which has a state of the name of the current frontmost app, or None if there isn't one. I'm really not sure how that can happen, but it's definitely possible. This updates via a signal when it changes, so it happens immediately.
Fixes#1184.
## Summary
This is the same sensor as we send up on iOS except it now bounces between No Connection, Wi-Fi and Ethernet.
## Link to pull request in Documentation repository
Documentation: home-assistant/companion.home-assistant#424
## Any other notes
- `sensor.connection_type` now has an `Ethernet` value and is set up on macOS.
- `sensor.connection_type` gains attributes on macOS: `Name` (the name of the network interface, e.g. `Wi-Fi`) and `Hardware Address` (the MAC address of the interface).
- Adds signaled updates to this (and other network) sensors.
Important to note that, although Ethernet is now added to Connection Type, the Wi-Fi sensors for SSID and BSSID will still report values if any Wi-Fi network device is connected, even if it is not the primary route.
Fixes#1247.
## Summary
Adds 3 sensors for displays: "Displays" (a count), "Primary Display Name" (the name of the display with the menu bar on it), and "Primary Display ID" (the ID of the primary).
## Link to pull request in Documentation repository
Documentation: home-assistant/companion.home-assistant#421
## Any other notes
- `sensor.displays`
- states like `0`, `1`, `2`, …
- attributes of `"Display IDs": ["id1", "id2", …]` and `"Display Names": ["name1", "name2", …]`
- `sensor.primary_display_name`
- states like `"None"`, `"Built-in Retina Display"`, etc.
- `sensor.primary_display_id`
- states like `"BE82E2E6-EA40-4963-93AD-A0BDC9D2F18F"`, `"1AB60A12-6BB3-4503-96BD-F5B481F5830E"` etc.
Breaking change. Fixes#1261.
Collapses all Camera and Microphone sensors from one-sensor-per-device to two camera and two microphone sensors:
- `binary_sensor.[device]_microphone_in_use` and `binary_sensor.[device]_camera_in_use` (value: true/false)
- `sensor.[device]_active_microphone` and `sensor.[device]_active_camera` (value: name or "Inactive")
This is unfortunately required because both the the `kCMIODevicePropertyDeviceUID`/`kAudioDevicePropertyDeviceUID` and the `kCMIOObjectPropertyName`/`kAudioObjectPropertyName` are not stable; the IDs change and names gain `#2`, `#3`, etc., suffixes. This is despite the documentation reading:
> A CMIODevice's UID is persistent across boots.
and
> An AudioDevice's UID is persistent across boots.
Were this the case, we wouldn't need to worry -- we unique on the device ID after all, and names can change over time were that part actually stable.
Pretty much does what it says on the tin.
Changes `zoneName` in `WebhookResponseLocationLocalMetadata` to be defined as `RLMZone.Name` rather than `RLMZone.ID`. This gives a friendlier name in notifications and event log titles, event payloads still show the entity ID.
(Likely; this is really hard to test) fixes a crash in the WatchApp when it's already in memory and the system wakes it to handle a background session completion event. What is happening is we're being killed after 25 seconds because we haven't completed the `WKURLSessionRefreshBackgroundTask`.
What I think is happening is that the background session processes and completes before the background task sets up the completion handlers, since the delegate method ends up jumping to the delegate dispatch queue of the background session.
This allows for configuring more than 1 e.g. Modular Small at a time. This requires watchOS 7; for releases before watchOS 7 we do not allow a secondary template to be created. This could be improved by allowing swapping between one of the multiple for watchOS 6 and earlier, but I didn't implement this.
- Adds a "Display Name" to Complications. This is optional and falls back to the template type. This is primarily to differentiate complications; the underlying unique ID is just a UUID.
- Enable previews of complications, which is used when selecting them. This is a stripped-down version of the items in the template, usually just an icon provider or one of the text providers. This is largely easier now since we're now requesting templates for all complications, even those not actively visible.
This also changes the flow when setting up initially. Instead of a list of families to choose from at the start, the user must tap the 'Add' button and pick one from there.
Fixes#839.
- Converts to String for the API-like things we provide for template rendering: intent handling and x-url-callback.
- Handles various kinds of results for Complication template handling: tries to smooth values to floats for percentile-based rings and gauges, describes via String for anywhere else.
- Adds a small amount of validation when entering templates in a Complication's Configuration.
Fixes#1177. Fixes#1180.
Running the latest Watch Extension on my device, I'm seeing a lot of kills like:
> Termination Reason: CAROUSEL, Background App Refresh watchdog transgression. Exhausted wall time allowance of 15.00 seconds.
From the [documentation on `WKApplicationRefreshBackgroundTask`](https://developer.apple.com/documentation/watchkit/wkapplicationrefreshbackgroundtask#), the suggestion is to kick off a background URLSession request and immediately end the app refresh task, allowing the background session code paths to complete the execution. Given we're being killed so often, I'm guessing that part'll work just fine.
Fixes#1191.
- Moves our background refresh timing from every 5 minutes to every 15 minutes. Apple [documents this](https://developer.apple.com/documentation/clockkit/updating_your_complication) as:
> The system carefully budgets background refresh tasks. You can schedule only one refresh task at a time. If you have a complication on the active watch face, you can safely schedule four refresh tasks a hour.
- When we refresh the rendering data backing complications, we now immediately tell ClockKit to invalidate/refresh our active complications. I'm not sure what was triggering refreshes before, but they were highly irregular. With this change, I can reliably see (at the new timing above) my complications update at around :00, :15, :30, and :45 on the hour.
- Stops restricting complication rendering to only the active complication. This makes switching between watch faces have the most accurate data possible, and is a very small increase in the size of this request/response -- we're already doing a network call, and the biggest cost of a network call is doing one more than the JSON payload size (which is small).
- Reduces how often we do complication updates on the iPhone side of thing. This doesn't help as much as I had thought it did; we're restricted in how often we can push watch data updates, and since we're not (yet?) using the "update the complications" WatchConnectivity feature, we're not necessarily directly forcing an update anyway.
- Reduces minorly how often we execute syncs on startup. If there's any synced Actions or NotificationCategory, this ends up doing 2+ syncs on startup; removing this restriction does 0-1, depending on if there's any synced. It always occurs when changes are made.
One of our top crashes (on all platforms) is crashing when completing the background refresh operation of the Watch Extension's update cycle. I believe this is because the task is being called more than once; presumably because we're mixing multiple types of tasks in one pointer -- communication updates and complication updates, and they stomp on each other.
Another issue here is that we're not using Background Sessions to do the complication updates, when we want to -- when I refactored Webhooks out of the HomeAssistantAPI code path, I neglected to update this Webhook call to handle background updating; it now does.
- Updates complication text rendering to go through the background session supporting Webhook update mechanism.
- Adds support for ring and gauge template rendering. Fixes#1127.
This is somewhat in prep of being able to make the project file generated, but also just organizes things into more concrete directory structures.
This pulls out _all_ of the build settings from the root level, and most from the target level, into xcconfigs.
The new directory structure looks like:
- Sources
- App
- (everything from HomeAssistant/)
- WatchApp
- Shared
- MacBridge
- Extensions
- Intents
- NotificationContent
- NotificationService
- Share
- Today
- Watch
- Widgets
- Tests
- App
- UI
- Shared
Somewhat intentionally, the file structure under these is not yet standardized/organized.
The project targets are now:
- App
- WatchApp
- Shared-iOS
- Shared-watchOS
- MacBridge
- Tests-App
- Tests-UI
- Tests-Shared
- Extension-Intents
- Extension-NotificationContent
- Extension-NotificationService
- Extension-Share
- Extension-Today
- Extension-Widget
- WatchExtension-Watch
This does not yet clean up resources vs. sources, nor does it handle some of the "it's in Sources/App but it's part of Shared" crossover directory issues.