Skill v1.0.1
currentAutomated scan100/100+3 new
version: "1.0.1" 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
MatterAddDeviceExtensionRequestHandler subclass
- 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 HomeKitlet 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 HomeKitfinal class HomeStore: NSObject, HMHomeManagerDelegate {let homeManager = HMHomeManager()override init() {super.init()homeManager.delegate = self}func homeManagerDidUpdateHomes(_ manager: HMHomeManager) {// Safe to access manager.homes nowlet homes = manager.homeslet primaryHome = manager.primaryHomeprint("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.roomslet kitchen = rooms.first { $0.name == "Kitchen" }// Room for accessories not assigned to a specific roomlet 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 discoveryhome.addAndSetupAccessories { error inif 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 inif let error {print("Failed to move accessory: \(error)")}}
Reading and Writing Characteristics
Reading a Value
let characteristic: HMCharacteristic = // obtained from a servicecharacteristic.readValue { error inguard error == nil else { return }if let value = characteristic.value as? Bool {print("Power state: \(value)")}}
Writing a Value
// Turn on a lightcharacteristic.writeValue(true) { error inif let error {print("Write failed: \(error)")}}
Observing Changes
Enable notifications for real-time updates:
characteristic.enableNotification(true) { error inguard 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 inguard let actionSet, error == nil else { return }// Turn off living room lightlet lightChar = livingRoomLight.powerCharacteristiclet action = HMCharacteristicWriteAction(characteristic: lightChar,targetValue: false as NSCopying)actionSet.addAction(action) { error inguard error == nil else { return }print("Action added to Good Night scene")}}
Executing an Action Set
home.executeActionSet(actionSet) { error inif let error {print("Execution failed: \(error)")}}
Creating a Timer Trigger
var timeOfDay = DateComponents()timeOfDay.hour = 22timeOfDay.minute = 30let 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 inguard error == nil else { return }// Attach the action set to the triggertrigger.addActionSet(goodNightActionSet) { error inguard error == nil else { return }trigger.enable(true) { error inprint("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 MatterSupportfunc 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 pairingtry 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 vendorlet 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 MatterSupportfinal 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 homereturn [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 backendprint("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 calledlet manager = HMHomeManager()let homes = manager.homes // Always empty here// CORRECT -- wait for delegatefunc 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 apphome.addAndSetupAccessories { error in }// CORRECT -- use MatterAddDeviceRequest for Matter ecosystem commissioninglet 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 independentlyclass ScreenA { let manager = HMHomeManager() }class ScreenB { let manager = HMHomeManager() }// CORRECT -- single shared instance@Observablefinal class HomeStore {static let shared = HomeStore()let homeManager = HMHomeManager()}
DON'T: Write characteristics without checking metadata
// WRONG -- writing a value outside the valid rangecharacteristic.writeValue(500) { _ in }// CORRECT -- check metadata firstif 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