How to install homekit
npx skills add https://github.com/dpearson2699/swift-ios-skills --skill homekitFull instructions (SKILL.md)
Source of truth, from dpearson2699/swift-ios-skills.
name: homekit description: "Control smart-home accessories and commission Matter devices using HomeKit and MatterSupport. Use when managing homes/rooms/accessories, creating action sets or triggers, reading accessory characteristics, onboarding Matter devices, or building a third-party smart-home ecosystem app."
HomeKit
Control home automation accessories and commission Matter devices. HomeKit manages the home/room/accessory model, action sets, and triggers. MatterSupport handles device commissioning into your ecosystem. Targets Swift 6.3 / iOS 26+.
Contents
- Setup
- HomeKit Data Model
- Managing Accessories
- Reading and Writing Characteristics
- Action Sets and Triggers
- Matter Commissioning
- MatterAddDeviceExtensionRequestHandler
- Common Mistakes
- Review Checklist
- References
Setup
HomeKit Configuration
- Enable the HomeKit capability in Xcode (Signing & Capabilities)
- Add
NSHomeKitUsageDescriptionto Info.plist:
<key>NSHomeKitUsageDescription</key>
<string>This app controls your smart home accessories.</string>
MatterSupport Configuration
For Matter commissioning into your own ecosystem:
- Add a MatterSupport Extension target and set its principal class to a
MatterAddDeviceExtensionRequestHandlersubclass - Add
NSBonjourServicesentries for_matter._tcp,_matterc._udp, and_matterd._udp - Add
com.apple.developer.matter.allow-setup-payloadonly if the caller supplies a Matter setup payload programmatically
Availability Check
import HomeKit
let homeManager = HMHomeManager()
// HomeKit is available on iPhone, iPad, Apple TV, Apple Watch,
// Mac Catalyst, and Vision Pro.
// Authorization is handled through the delegate:
homeManager.delegate = self
HomeKit Data Model
HomeKit organizes home automation in a hierarchy:
HMHomeManager
-> HMHome (one or more)
-> HMRoom (rooms in the home)
-> HMAccessory (devices in a room)
-> HMService (functions: light, thermostat, etc.)
-> HMCharacteristic (readable/writable values)
-> HMZone (groups of rooms)
-> HMActionSet (grouped actions)
-> HMTrigger (time or event-based triggers)
Initializing the Home Manager
Create a single HMHomeManager and implement the delegate to know when
data is loaded. HomeKit loads asynchronously -- do not access homes until
the delegate fires.
import HomeKit
final class HomeStore: NSObject, HMHomeManagerDelegate {
let homeManager = HMHomeManager()
override init() {
super.init()
homeManager.delegate = self
}
func homeManagerDidUpdateHomes(_ manager: HMHomeManager) {
// Safe to access manager.homes now
let homes = manager.homes
let primaryHome = manager.primaryHome
print("Loaded \(homes.count) homes")
}
func homeManager(
_ manager: HMHomeManager,
didUpdate status: HMHomeManagerAuthorizationStatus
) {
if status.contains(.authorized) {
print("HomeKit access granted")
}
}
}
Accessing Rooms
guard let home = homeManager.primaryHome else { return }
let rooms = home.rooms
let kitchen = rooms.first { $0.name == "Kitchen" }
// Room for accessories not assigned to a specific room
let defaultRoom = home.roomForEntireHome()
Managing Accessories
Discovering and Adding Accessories
Use HomeKit and MatterSupport for home-model work: homes, rooms, HMAccessory services and characteristics, action sets, triggers and automations, HomeKit accessory setup UI, and Matter commissioning. If the same request asks about lower-level Bluetooth or Wi-Fi accessory discovery or authorization, name AccessorySetupKit as the boundary for discovery descriptors, picker authorization, ASAccessorySession events, and migration. After AccessorySetupKit setup, explicitly name both post-setup handoff targets: CoreBluetooth/GATT for Bluetooth accessories and NetworkExtension for Wi-Fi accessory network flows; neither handoff is HomeKit automation logic.
// System UI for accessory discovery
home.addAndSetupAccessories { error in
if let error {
print("Setup failed: \(error)")
}
}
Listing Accessories and Services
for accessory in home.accessories {
print("\(accessory.name) in \(accessory.room?.name ?? "unassigned")")
for service in accessory.services {
print(" Service: \(service.serviceType)")
for characteristic in service.characteristics {
print(" \(characteristic.characteristicType): \(characteristic.value ?? "nil")")
}
}
}
Moving an Accessory to a Room
guard let accessory = home.accessories.first,
let bedroom = home.rooms.first(where: { $0.name == "Bedroom" }) else { return }
home.assignAccessory(accessory, to: bedroom) { error in
if let error {
print("Failed to move accessory: \(error)")
}
}
Reading and Writing Characteristics
Reading a Value
let characteristic: HMCharacteristic = // obtained from a service
characteristic.readValue { error in
guard error == nil else { return }
if let value = characteristic.value as? Bool {
print("Power state: \(value)")
}
}
Writing a Value
// Turn on a light
characteristic.writeValue(true) { error in
if let error {
print("Write failed: \(error)")
}
}
Observing Changes
Enable notifications for real-time updates:
characteristic.enableNotification(true) { error in
guard error == nil else { return }
}
// In HMAccessoryDelegate:
func accessory(
_ accessory: HMAccessory,
service: HMService,
didUpdateValueFor characteristic: HMCharacteristic
) {
print("Updated: \(characteristic.value ?? "nil")")
}
Action Sets and Triggers
Creating an Action Set
An HMActionSet groups characteristic writes that execute together:
home.addActionSet(withName: "Good Night") { actionSet, error in
guard let actionSet, error == nil else { return }
// Turn off living room light
let lightChar = livingRoomLight.powerCharacteristic
let action = HMCharacteristicWriteAction(
characteristic: lightChar,
targetValue: false as NSCopying
)
actionSet.addAction(action) { error in
guard error == nil else { return }
print("Action added to Good Night scene")
}
}
Executing an Action Set
home.executeActionSet(actionSet) { error in
if let error {
print("Execution failed: \(error)")
}
}
Creating a Timer Trigger
var timeOfDay = DateComponents()
timeOfDay.hour = 22
timeOfDay.minute = 30
let firstFireDate = Calendar.current.nextDate(
after: Date(),
matching: timeOfDay,
matchingPolicy: .nextTime
)!
let trigger = HMTimerTrigger(
name: "Nightly",
fireDate: firstFireDate,
recurrence: DateComponents(day: 1) // Repeat every day after firstFireDate
)
home.addTrigger(trigger) { error in
guard error == nil else { return }
// Attach the action set to the trigger
trigger.addActionSet(goodNightActionSet) { error in
guard error == nil else { return }
trigger.enable(true) { error in
print("Trigger enabled: \(error == nil)")
}
}
}
Creating an Event Trigger
let motionDetected = HMCharacteristicEvent(
characteristic: motionSensorCharacteristic,
triggerValue: true as NSCopying
)
let eventTrigger = HMEventTrigger(
name: "Motion Lights",
events: [motionDetected],
predicate: nil
)
home.addTrigger(eventTrigger) { error in
// Add action sets as above
}
Matter Commissioning
Use MatterAddDeviceRequest to commission a Matter device into your ecosystem.
This is separate from the HMHome home-automation model; it handles the
Matter setup flow and calls into your MatterSupport extension.
Basic Commissioning
import MatterSupport
func addMatterDevice() async throws {
guard MatterAddDeviceRequest.isSupported else {
print("Matter not supported on this device")
return
}
let topology = MatterAddDeviceRequest.Topology(
ecosystemName: "My Smart Home",
homes: [
MatterAddDeviceRequest.Home(displayName: "Main House")
]
)
let request = MatterAddDeviceRequest(
topology: topology,
setupPayload: nil,
showing: .allDevices
)
// Presents system UI for device pairing
try await request.perform()
}
When providing a setup code directly, import Matter and pass an
MTRSetupPayload as setupPayload; this is the case that requires the
setup-payload entitlement.
Filtering Devices
// Only show devices from a specific vendor
let criteria = MatterAddDeviceRequest.DeviceCriteria.vendorID(0x1234)
let request = MatterAddDeviceRequest(
topology: topology,
setupPayload: nil,
showing: criteria
)
Combine criteria with .all([.vendorID(...), .not(.productID(...))]) or use
.any(...) when any one criterion is enough.
MatterAddDeviceExtensionRequestHandler
For full ecosystem support, create a MatterSupport Extension. The extension
handles commissioning callbacks. Override the needed methods, but do not call
super from those overrides.
import MatterSupport
final class MatterHandler: MatterAddDeviceExtensionRequestHandler {
override func validateDeviceCredential(
_ deviceCredential:
MatterAddDeviceExtensionRequestHandler.DeviceCredential
) async throws {
// Validate the device attestation certificate
// Throw to reject the device
}
override func rooms(
in home: MatterAddDeviceRequest.Home?
) async -> [MatterAddDeviceRequest.Room] {
// Return rooms in the selected home
return [
MatterAddDeviceRequest.Room(displayName: "Living Room"),
MatterAddDeviceRequest.Room(displayName: "Kitchen")
]
}
override func configureDevice(
named name: String,
in room: MatterAddDeviceRequest.Room?
) async {
// Save the device configuration to your backend
print("Configuring \(name) in \(room?.displayName ?? "no room")")
}
override func commissionDevice(
in home: MatterAddDeviceRequest.Home?,
onboardingPayload: String,
commissioningID: UUID
) async throws {
// Use the onboarding payload to commission the device
// into your fabric using the Matter framework
}
}
Common Mistakes
DON'T: Access homes before the delegate fires
// WRONG -- homes array is empty until delegate is called
let manager = HMHomeManager()
let homes = manager.homes // Always empty here
// CORRECT -- wait for delegate
func homeManagerDidUpdateHomes(_ manager: HMHomeManager) {
let homes = manager.homes // Now populated
}
DON'T: Confuse HomeKit setup with Matter commissioning
// WRONG -- using HomeKit accessory setup for a Matter ecosystem app
home.addAndSetupAccessories { error in }
// CORRECT -- use MatterAddDeviceRequest for Matter ecosystem commissioning
let request = MatterAddDeviceRequest(
topology: topology,
setupPayload: nil,
showing: .allDevices
)
try await request.perform()
DON'T: Forget required configuration
Matter ecosystem commissioning needs the MatterSupport extension, principal handler class, and Matter Bonjour services. Add the setup-payload entitlement only when your app provides setup codes directly.
DON'T: Create multiple HMHomeManager instances
// WRONG -- each instance loads the full database independently
class ScreenA { let manager = HMHomeManager() }
class ScreenB { let manager = HMHomeManager() }
// CORRECT -- single shared instance
@Observable
final class HomeStore {
static let shared = HomeStore()
let homeManager = HMHomeManager()
}
DON'T: Write characteristics without checking metadata
// WRONG -- writing a value outside the valid range
characteristic.writeValue(500) { _ in }
// CORRECT -- check metadata first
if let metadata = characteristic.metadata,
let maxValue = metadata.maximumValue?.intValue {
let safeValue = min(brightness, maxValue)
characteristic.writeValue(safeValue) { _ in }
}
Review Checklist
- HomeKit capability enabled in Xcode
-
NSHomeKitUsageDescriptionpresent in Info.plist - Single
HMHomeManagerinstance shared across the app -
HMHomeManagerDelegateimplemented; homes not accessed beforehomeManagerDidUpdateHomes -
HMHomeDelegateset on homes to receive accessory and room changes -
HMAccessoryDelegateset on accessories to receive characteristic updates - Characteristic metadata checked before writing values
- Error handling in all completion handlers
- MatterSupport extension target and principal handler configured
- Matter discovery
NSBonjourServicesentries added -
com.apple.developer.matter.allow-setup-payloadused only when providing setup codes -
MatterAddDeviceRequest.isSupportedchecked before performing requests - Matter extension handler implements
commissionDevice(in:onboardingPayload:commissioningID:) - Action sets tested with the HomeKit Accessory Simulator before shipping
- Triggers enabled after creation (
trigger.enable(true))
References
- Extended patterns (Matter extension, delegate wiring, SwiftUI): references/matter-commissioning.md
- HomeKit framework
- HMHomeManager
- HMHome
- HMAccessory
- HMRoom
- HMActionSet
- HMTrigger
- MatterSupport framework
- MatterAddDeviceRequest
- MatterAddDeviceExtensionRequestHandler
- Enabling HomeKit in your app
- Adding Matter support to your ecosystem
Related skills
More from dpearson2699/swift-ios-skills and the wider catalog.
swiftui-animation
Implement, review, or improve SwiftUI animations and transitions. Use when adding explicit animations with withAnimation, configuring implicit animations with .animation(_:body:) or .animation(_:value:), configuring spring animations (.smooth, .snappy, .bouncy), building phase or keyframe animations with PhaseAnimator/KeyframeAnimator, creating hero transitions with matchedGeometryEffect or matchedTransitionSource, adding SF Symbol effects (iOS 17 bounce, pulse, variableColor, scale, appear, disappear, replace; iOS 18 breathe, rotate, wiggle), implementing custom Transition or CustomAnimation types, or ensuring animations respect accessibilityReduceMotion.
ios-accessibility
Implements, reviews, or improves accessibility in iOS/macOS apps with SwiftUI, UIKit, and AppKit. Use when adding VoiceOver, Voice Control, Switch Control, or Full Keyboard Access support; when working with accessibility labels, hints, values, traits, accessibilityInputLabels, NSAccessibility, grouping, reading order, accessibility focus restoration with @AccessibilityFocusState, Dynamic Type, @ScaledMetric, custom rotors, accessibility actions, XCTest accessibility checks, App Store Accessibility Nutrition Labels, App Store Connect accessibility answers, a11y compliance audits, or system accessibility preferences.
swiftui-patterns
Builds and reviews SwiftUI views with modern MV architecture, state management, view composition, and migration/availability guidance. Covers @Observable ownership rules, @State/@Bindable/@Environment wiring, view decomposition, custom ViewModifiers, environment values, async data loading with .task, iOS 26+ handoff reminders, Writing Tools, clipboard availability caveats, and performance guidelines. Use when structuring SwiftUI app state, managing @Observable, composing view hierarchies, or correcting SwiftUI pattern guidance.
swiftui-performance
Audit and improve SwiftUI runtime performance. Use when diagnosing slow rendering, janky scrolling, high CPU, memory usage, excessive view updates, layout thrash, body evaluation cost, identity churn, view lifetime issues, lazy loading, Instruments profiling guidance, and performance audit requests.
app-store-review
Prepare for App Store review and prevent rejections. Covers App Store review guidelines, app rejection reasons, PrivacyInfo.xcprivacy privacy manifest requirements, required API reason codes, in-app purchase IAP and StoreKit rules, App Store Guidelines compliance, ATT App Tracking Transparency, EU DMA Digital Markets Act, HIG compliance checklist, app submission preparation, review preparation, metadata requirements, entitlements, widgets, and Live Activities review rules. Use when preparing for App Store submission, fixing rejection reasons, auditing privacy manifests, implementing ATT consent flow, configuring StoreKit IAP, or checking HIG compliance.
ios-networking
Build, review, or improve networking code in iOS/macOS apps using URLSession with async/await, structured concurrency, and modern Swift patterns. Use when working with REST APIs, downloading files, uploading data, WebSocket connections, pagination, retry logic, request middleware, caching, background transfers, or network reachability monitoring. Also use when handling HTTP requests, API clients, network error handling, or data fetching in Swift apps.