Skip to content
All essays
iOSMarch 27, 202512 min

Swift HomeKit: Smart Home Integration

Integrate with HomeKit to control smart home devices. Accessories, services, and automation.

Ü
Ümit Uz
Mobile & Full Stack Developer

HomeKit enables your app to control smart home accessories. Learn to integrate with HomeKit and create home automation.

HomeKit Setup

Configure HomeKit

  1. 1Go to Project Settings > Signing & Capabilities
  2. 2Add "HomeKit" capability
  3. 3Enable HomeKit in Entitlements

Import HomeKit

swift
import HomeKit
import SwiftUI

class HomeManager: NSObject, ObservableObject, HMHomeManagerDelegate {
    private let homeManager = HMHomeManager()

    @Published var homes: [HMHome] = []
    @Published var accessories: [HMAccessory] = []
    @Published var authorizationStatus: HMHomeManagerAuthorizationStatus = .determined

    override init() {
        super.init()
        homeManager.delegate = self
    }

    func requestAuthorization() {
        homeManager.requestAuthorization { status in
            DispatchQueue.main.async {
                self.authorizationStatus = status
            }
        }
    }

    func loadHomes() {
        homes = homeManager.homes
        updateAccessories()
    }

    func updateAccessories() {
        guard let home = homes.first else { return }
        accessories = home.accessories ?? []
    }
}

Accessories

Discover Accessories

swift
extension HomeManager {
    func addAccessory(completion: @escaping (Bool) -> Void) {
        homeManager.addAndSetupAccessories { error in
            if let error = error {
                print("Error adding accessory: \(error)")
                completion(false)
            } else {
                self.loadHomes()
                completion(true)
            }
        }
    }

    func removeAccessory(_ accessory: HMAccessory, from home: HMHome) {
        home.removeAccessory(accessory) { error in
            if let error = error {
                print("Error removing accessory: \(error)")
            } else {
                self.updateAccessories()
            }
        }
    }
}

Services and Characteristics

Control Accessories

swift
class AccessoryController: ObservableObject {
    @Published var isOn = false
    @Published var brightness = 0.5

    func toggleLight(_ accessory: HMAccessory) {
        guard let service = accessory.services.first(where: { $0.serviceType == .lightbulb }) else {
            return
        }

        guard let powerCharacteristic = service.characteristics.first(where: { $0.characteristicType == .powerState }) else {
            return
        }

        let targetValue: Bool = !isOn

        powerCharacteristic.writeValue(targetValue) { error in
            if let error = error {
                print("Error toggling light: \(error)")
            } else {
                DispatchQueue.main.async {
                    self.isOn = targetValue
                }
            }
        }
    }

    func setBrightness(_ value: Int, for accessory: HMAccessory) {
        guard let service = accessory.services.first(where: { $0.serviceType == .lightbulb }) else {
            return
        }

        guard let brightnessCharacteristic = service.characteristics.first(where: { $0.characteristicType == .brightness }) else {
            return
        }

        brightnessCharacteristic.writeValue(value) { error in
            if let error = error {
                print("Error setting brightness: \(error)")
            } else {
                DispatchQueue.main.async {
                    self.brightness = Double(value) / 100.0
                }
            }
        }
    }
}

Home Automation

Create Triggers

swift
extension HomeManager {
    func createTrigger(name: String, condition: HMTriggerCondition, actionSet: HMActionSet) {
        guard let home = homes.first else { return }

        let trigger = HMTrigger(name: name, conditions: [condition], actions: [actionSet])

        home.addActionSet(actionSet) { error in
            if let error = error {
                print("Error adding action set: \(error)")
            } else {
                home.addTrigger(trigger) { error in
                    if let error = error {
                        print("Error adding trigger: \(error)")
                    }
                }
            }
        }
    }

    func createTimeTrigger(hour: Int, minute: Int, actionSet: HMActionSet) {
        let dateComponents = DateComponents(hour: hour, minute: minute)
        let condition = HMEventTrigger(condition: HMCalendarEvent(condition: dateComponents))

        createTrigger(
            name: "Time Trigger",
            condition: condition,
            actionSet: actionSet
        )
    }
}

Action Sets

Define Actions

swift
extension HomeManager {
    func createActionSet(name: String, actions: [HMAction]) -> HMActionSet {
        let actionSet = HMActionSet(name: name, actions: actions)
        return actionSet
    }

    func createLightAction(accessory: HMAccessory, isOn: Bool, brightness: Int) -> HMAction? {
        guard let service = accessory.services.first(where: { $0.serviceType == .lightbulb }) else {
            return nil
        }

        var actions: [HMAction] = []

        // Power action
        if let powerCharacteristic = service.characteristics.first(where: { $0.characteristicType == .powerState }) {
            let powerAction = HMCharacteristicAction(
                characteristic: powerCharacteristic,
                value: isOn
            )
            actions.append(powerAction)
        }

        // Brightness action
        if let brightnessCharacteristic = service.characteristics.first(where: { $0.characteristicType == .brightness }) {
            let brightnessAction = HMCharacteristicAction(
                characteristic: brightnessCharacteristic,
                value: brightness
            )
            actions.append(brightnessAction)
        }

        return actions.count > 0 ? HMActionSet(name: "Light Actions", actions: actions) : nil
    }
}

Characteristic Monitoring

Listen for Changes

swift
class CharacteristicMonitor {
    func monitorCharacteristic(_ characteristic: HMCharacteristic) {
        characteristic.enableNotification { error in
            if let error = error {
                print("Error enabling notification: \(error)")
                return
            }

            // Add observer
            NotificationCenter.default.addObserver(
                forName: HMCharacteristicValueDidChangeNotification,
                object: characteristic,
                queue: .main
            ) { notification in
                if let updatedCharacteristic = notification.object as? HMCharacteristic {
                    self.handleCharacteristicChange(updatedCharacteristic)
                }
            }
        }
    }

    func handleCharacteristicChange(_ characteristic: HMCharacteristic) {
        if let value = characteristic.value as? Bool {
            print("Power state changed: \(value)")
        } else if let value = characteristic.value as? Int {
            print("Value changed: \(value)")
        }
    }
}

Rooms and Zones

Organize Accessories

swift
extension HomeManager {
    func createRoom(name: String, in home: HMHome) {
        home.addRoom(withName: name) { room, error in
            if let room = room {
                print("Room created: \(room.name)")
            } else {
                print("Error creating room: \(error)")
            }
        }
    }

    func addAccessory(_ accessory: HMAccessory, to room: HMRoom) {
        room.addAccessory(accessory) { error in
            if let error = error {
                print("Error adding accessory to room: \(error)")
            }
        }
    }

    func createZone(name: String, in home: HMHome, rooms: [HMRoom]) {
        home.addZone(withName: name, rooms: rooms) { zone, error in
            if let zone = zone {
                print("Zone created: \(zone.name)")
            } else {
                print("Error creating zone: \(error)")
            }
        }
    }
}

Siri Integration

Custom Siri Commands

swift
extension HomeManager {
    func createCustomSiriPhrase(name: String, phrase: String, actionSet: HMActionSet) {
        guard let home = homes.first else { return }

        let trigger = HMAccessoryControlTrigger(
            name: name,
            conditions: [],
            actionSets: [actionSet]
        )

        home.addTrigger(trigger) { error in
            if let error = error {
                print("Error adding Siri trigger: \(error)")
            } else {
                print("Siri phrase added: \(phrase)")
            }
        }
    }
}

SwiftUI Integration

Home Control View

swift
struct HomeControlView: View {
    @StateObject private var homeManager = HomeManager()
    @StateObject private var accessoryController = AccessoryController()

    var body: some View {
        NavigationView {
            List(homeManager.accessories) { accessory in
                AccessoryRow(
                    accessory: accessory,
                    controller: accessoryController
                )
            }
            .navigationTitle("Home")
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button("Add Accessory") {
                        homeManager.addAccessory { success in
                            print("Accessory added: \(success)")
                        }
                    }
                }
            }
        }
        .task {
            homeManager.requestAuthorization()
            homeManager.loadHomes()
        }
    }
}

struct AccessoryRow: View {
    let accessory: HMAccessory
    let controller: AccessoryController

    var body: some View {
        HStack {
            VStack(alignment: .leading) {
                Text(accessory.name ?? "Unknown")
                    .font(.headline)
                Text(accessory.room?.name ?? "Unassigned")
                    .font(.caption)
                    .foregroundColor(.secondary)
            }

            Spacer()

            Toggle("", isOn: Binding(
                get: { controller.isOn },
                set: { _ in controller.toggleLight(accessory) }
            )
        }
    }
}

Best Practices

  1. 1Authorization: Request authorization appropriately
  2. 2Error Handling: Handle HomeKit errors gracefully
  3. 3UI: Provide intuitive control interface
  4. 4Performance: Optimize for performance
  5. 5Testing: Test with real HomeKit accessories
  6. 6Updates: Handle accessory updates
  7. 7Siri: Implement custom Siri commands
  8. 8Security: Maintain security best practices

HomeKit enables seamless smart home integration!

Related essays

Next essay
Swift HealthKit: Health Data Integration