mcpField
H
homekit-matter

homekit-matter

github.com/dpearson2699開発1.2k402 回インストール13 週間前に更新
リポジトリ

homekit-matter について

HomeKit と MatterSupport を扱う iOS 開発者向けの Swift スキルです。ホームやアクセサリの管理、特性の制御、自動化、Matter デバイスのエコシステムへのコミッショニングを解説します。

主な機能

  1. 01ホーム・部屋・アクセサリ・サービスの管理
  2. 02特性値の読み書きと変更監視
  3. 03アクションセットとトリガーの作成
  4. 04MatterSupport によるデバイスのペアリング
  5. 05権限と構成要件の確認

活用シーン

  1. 01スマートホームのアクセサリ管理機能を構築
  2. 02照明などの特性値を制御
  3. 03時間・イベント起点のホームアクションを設定
  4. 04Matter デバイスをエコシステムに追加

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/dpearson2699/swift-ios-skills --skill homekit-matter

インストール後、Claude Code で/homekit-matterを入力して読み込まれたか確認します。

同梱ファイルreferences/matter-commissioning.md

詳細

HomeKit + MatterSupport

ホームオートメーションアクセサリを操作し、Matter デバイスをコミッショニングします。HomeKit はホーム/部屋/アクセサリのモデル、アクションセット、トリガーを管理します。MatterSupport は、デバイスをエコシステムにコミッショニングします。対象は Swift 6.2/iOS 26 以降です。

目次

セットアップ

HomeKit の設定
  1. Xcode で HomeKit 機能を有効にします(Signing & Capabilities)
  2. Info.plist に NSHomeKitUsageDescription を追加します。
<key>NSHomeKitUsageDescription</key>
<string>This app controls your smart home accessories.</string>
MatterSupport の設定

独自のエコシステムに Matter をコミッショニングする場合:

  1. MatterSupport 機能を有効にします
  2. プロジェクトに MatterSupport Extension ターゲットを追加します
  3. アプリがセットアップコードを直接提供する場合は、com.apple.developer.matter.allow-setup-payload エンタイトルメントを追加します
利用可能かどうかの確認
import HomeKit

let homeManager = HMHomeManager()

// HomeKit is available on iPhone, iPad, Apple TV, Apple Watch, Mac, and Vision Pro.
// Authorization is handled through the delegate:
homeManager.delegate = self

HomeKit データモデル

HomeKit はホームオートメーションを階層構造で整理します。

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)
ホームマネージャーの初期化

HMHomeManager を 1 つ作成し、データの読み込み完了を確認できるようにデリゲートを実装します。HomeKit の読み込みは非同期です。デリゲートが呼び出されるまでは homes にアクセスしないでください。

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")
        }
    }
}
部屋へのアクセス
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()

アクセサリの管理

アクセサリの検出と追加
// System UI for accessory discovery
home.addAndSetupAccessories { error in
    if let error {
        print("Setup failed: \(error)")
    }
}
アクセサリとサービスの一覧表示
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")")
        }
    }
}
アクセサリを部屋に移動する
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)")
    }
}

特性の読み取りと書き込み

値の読み取り
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)")
    }
}
値の書き込み
// Turn on a light
characteristic.writeValue(true) { error in
    if let error {
        print("Write failed: \(error)")
    }
}
変更の監視

リアルタイム更新を有効にします。

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")")
}

アクションセットとトリガー

アクションセットの作成

HMActionSet は、まとめて実行される特性への書き込みをグループ化します。

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")
    }
}
アクションセットの実行
home.executeActionSet(actionSet) { error in
    if let error {
        print("Execution failed: \(error)")
    }
}
タイマートリガーの作成
var dateComponents = DateComponents()
dateComponents.hour = 22
dateComponents.minute = 30

let trigger = HMTimerTrigger(
    name: "Nightly",
    fireDate: Calendar.current.nextDate(
        after: Date(),
        matching: dateComponents,
        matchingPolicy: .nextTime
    )!,
    timeZone: .current,
    recurrence: dateComponents,  // Repeats daily at 22:30
    recurrenceCalendar: .current
)

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)")
        }
    }
}
イベントトリガーの作成
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 のコミッショニング

MatterAddDeviceRequest を使用して、Matter デバイスをエコシステムにコミッショニングします。これは HomeKit とは別のもので、ペアリングフローを処理します。

基本的なコミッショニング
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()
}
デバイスのフィルタリング
// Only show devices from a specific vendor
let criteria = MatterAddDeviceRequest.DeviceCriteria.vendorID(0x1234)

let request = MatterAddDeviceRequest(
    topology: topology,
    setupPayload: nil,
    showing: criteria
)
デバイス条件の組み合わせ
let criteria = MatterAddDeviceRequest.DeviceCriteria.all([
    .vendorID(0x1234),
    .not(.productID(0x0001))  // Exclude a specific product
])

MatterAddDeviceExtensionRequestHandler

エコシステムを完全にサポートするには、MatterSupport Extension を作成します。このエクステンションはコミッショニングのコールバックを処理します。

import MatterSupport

final class MatterHandler: MatterAddDeviceExtensionRequestHandler {

    override func validateDeviceCredential(
        _ deviceCredential: 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
    }
}

よくある間違い

してはいけないこと:デリゲートの呼び出し前に homes にアクセスする
// 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
}
してはいけないこと:HomeKit のセットアップと Matter のコミッショニングを混同する
// 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()
してはいけないこと:必要なエンタイトルメントを忘れる
// WRONG -- calling Matter APIs without the MatterSupport entitlement
// Results in runtime error

// CORRECT -- ensure these are set up:
// 1. HomeKit capability for HMHomeManager access
// 2. MatterSupport Extension target for ecosystem commissioning
// 3. com.apple.developer.matter.allow-setup-payload if providing setup codes
してはいけないこと:複数の HMHomeManager インスタンスを作成する
// 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()
}
してはいけないこと:メタデータを確認せずに特性を書き込む
// 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 }
}

レビュー用チェックリスト

  • Xcode で HomeKit 機能を有効にしている
  • Info.plist に NSHomeKitUsageDescription が記載されている
  • アプリ全体で単一の HMHomeManager インスタンスを共有している
  • HMHomeManagerDelegate を実装している。homeManagerDidUpdateHomes の呼び出し前に homes にアクセスしていない
  • アクセサリと部屋の変更を受け取れるよう、ホームに HMHomeDelegate を設定している
  • 特性の更新を受け取れるよう、アクセサリに HMAccessoryDelegate を設定している
  • 値を書き込む前に特性のメタデータを確認している
  • すべての完了ハンドラーでエラー処理を行っている
  • Matter のコミッショニング用に MatterSupport 機能とエクステンションターゲットを追加している
  • リクエストを実行する前に MatterAddDeviceRequest.isSupported を確認している
  • Matter エクステンションのハンドラーで commissionDevice(in:onboardingPayload:commissioningID:) を実装している
  • リリース前に HomeKit Accessory Simulator でアクションセットをテストしている
  • 作成後にトリガーを有効にしている(trigger.enable(true))

参考資料

コメント