iOS-only: Apple Home-Lampen reagieren auf Mood-Wechsel parallel
zur direkten Hue-Bridge. Trade-off: HomeKit rate-limited (~10Hz),
für Mood-Switches okay, für Beat-Sync zu langsam.
Was:
- Sources/Core/SmartHome/HomeKitController.swift @Observable +
HMHomeManagerDelegate:
- start(): triggert iOS-HomeKit-Permission-Prompt
- LampAccessory-Indexer extrahiert nur Lightbulb-Services, gruppiert
nach Room
- applyMood schreibt Hue/Saturation/Brightness/PowerState pro
Accessory mit RGB→HSV-Konvertierung (HomeKit-Skala: h 0-360,
s/v 0-100)
- Selected-Lamps in App-Group-UserDefaults
- turnOffSelected() beim Player-Close
- Sources/Features/Settings/HomeKitSettingsView.swift: Permission-State-
Anzeige + Lamps gruppiert nach Room mit Multi-Select-Toggle
- SettingsView: NavigationLink zu HomeKitSettingsView (iOS-only)
- MoodPlayerView: pushToHomeKit() + turnOffHomeLights() parallel zu Hue
- project.yml: NSHomeKitUsageDescription + NSLocalNetworkUsageDescription
in Info.plist, com.apple.developer.homekit-Entitlement
(Apple-Dev-Portal-Capability-Aktivierung steht noch aus)
primaryHome → homes.first weil iOS-16.1-Deprecation.
Build iOS+macOS grün, 18/18 Tests grün.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
121 lines
3.2 KiB
Swift
121 lines
3.2 KiB
Swift
#if os(iOS)
|
|
import SwiftUI
|
|
|
|
/// Setup-UI für HomeKit-Lampen. Permission-Request → Room-/Lamp-Liste
|
|
/// → Per-Lamp-Toggle. Persistiert in App-Group-UserDefaults.
|
|
public struct HomeKitSettingsView: View {
|
|
@Environment(HomeKitController.self) private var controller
|
|
|
|
public init() {}
|
|
|
|
public var body: some View {
|
|
Form {
|
|
authSection
|
|
if controller.authState == .authorized {
|
|
if controller.availableLamps.isEmpty {
|
|
emptyHomeSection
|
|
} else {
|
|
lampsSection
|
|
}
|
|
}
|
|
infoSection
|
|
}
|
|
.navigationTitle("Apple Home")
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
.onAppear {
|
|
controller.start()
|
|
}
|
|
}
|
|
|
|
@ViewBuilder
|
|
private var authSection: some View {
|
|
Section {
|
|
switch controller.authState {
|
|
case .notRequested:
|
|
Label("Bereit", systemImage: "house")
|
|
case .requesting:
|
|
HStack(spacing: 12) {
|
|
ProgressView()
|
|
Text("Lade HomeKit …")
|
|
}
|
|
case .authorized:
|
|
Label("HomeKit erlaubt", systemImage: "checkmark.circle.fill")
|
|
.foregroundStyle(.green)
|
|
case .denied:
|
|
VStack(alignment: .leading, spacing: 6) {
|
|
Label("HomeKit-Zugriff verweigert", systemImage: "lock")
|
|
.foregroundStyle(.orange)
|
|
Text("Aktiviere in den iPhone-Einstellungen → Datenschutz → HomeKit → Moodlit.")
|
|
.font(.caption)
|
|
.foregroundStyle(MoodlitTheme.mutedForeground)
|
|
}
|
|
case .restricted:
|
|
Label(
|
|
"HomeKit ist auf diesem Gerät systemseitig eingeschränkt.",
|
|
systemImage: "exclamationmark.triangle"
|
|
)
|
|
.foregroundStyle(.orange)
|
|
}
|
|
}
|
|
}
|
|
|
|
@ViewBuilder
|
|
private var emptyHomeSection: some View {
|
|
Section {
|
|
VStack(alignment: .leading, spacing: 6) {
|
|
Text("Kein HomeKit-Zuhause oder keine kompatiblen Lampen gefunden.")
|
|
.font(.body)
|
|
Text("Lege in der Home-App ein Zuhause an und füge Lampen hinzu. Sie erscheinen dann hier.")
|
|
.font(.caption)
|
|
.foregroundStyle(MoodlitTheme.mutedForeground)
|
|
}
|
|
}
|
|
}
|
|
|
|
@ViewBuilder
|
|
private var lampsSection: some View {
|
|
let grouped = Dictionary(grouping: controller.availableLamps, by: \.room)
|
|
ForEach(grouped.keys.sorted { ($0 ?? "z") < ($1 ?? "z") }, id: \.self) { room in
|
|
Section(room ?? "Ohne Raum") {
|
|
ForEach(grouped[room] ?? []) { lamp in
|
|
Button {
|
|
controller.toggleSelected(lampId: lamp.id)
|
|
} label: {
|
|
HStack(spacing: 12) {
|
|
Image(systemName: controller.selectedLampIds.contains(lamp.id)
|
|
? "checkmark.circle.fill"
|
|
: "circle"
|
|
)
|
|
.foregroundStyle(
|
|
controller.selectedLampIds.contains(lamp.id)
|
|
? MoodlitTheme.primary
|
|
: MoodlitTheme.mutedForeground
|
|
)
|
|
VStack(alignment: .leading, spacing: 2) {
|
|
Text(lamp.name)
|
|
if !lamp.supportsColor {
|
|
Text("nur Helligkeit")
|
|
.font(.caption2)
|
|
.foregroundStyle(MoodlitTheme.mutedForeground)
|
|
}
|
|
}
|
|
Spacer()
|
|
}
|
|
}
|
|
.buttonStyle(.plain)
|
|
.contentShape(Rectangle())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@ViewBuilder
|
|
private var infoSection: some View {
|
|
Section {
|
|
Text("HomeKit ist langsamer als die direkte Hue-Anbindung (max ~10 Updates pro Sekunde pro Lampe). Für Mood-Wechsel okay, für Beat-Sync zu langsam — dann lieber direkten Hue-Bridge-Pfad nutzen.")
|
|
.font(.caption)
|
|
.foregroundStyle(MoodlitTheme.mutedForeground)
|
|
}
|
|
}
|
|
}
|
|
#endif
|