mirror of
https://github.com/openclaw/casa.git
synced 2026-07-01 20:54:20 -04:00
bda9995ed8
- GET /homekit/scenes — list all scenes with id, name, homeId, type, isExecuting - POST /homekit/scenes/:id/execute — execute a scene by UUID Server: - HomeKitManager: scenes property, scene(with:) lookup, executeScene() async - HomeKitServer: route handling for GET and POST with homeKit-disabled guard - HomeKitPayload/HomeKitMapper: CasaScene model and JSON serialization UI: - Sidebar: new Scenes section with 'All scenes' + per-scene rows - Selecting a scene switches API docs to show scene-specific endpoints - Scene filter dropdown mirrors existing accessory filter for consistency - Accessory and scene selections are mutually exclusive
97 lines
2.9 KiB
Swift
97 lines
2.9 KiB
Swift
import Foundation
|
|
import HomeKit
|
|
|
|
@MainActor
|
|
final class HomeKitManager: NSObject, ObservableObject {
|
|
private let manager = HMHomeManager()
|
|
private let logger: CasaLogger
|
|
|
|
@Published private(set) var homes: [HMHome] = []
|
|
@Published private(set) var accessories: [HMAccessory] = []
|
|
|
|
init(logger: CasaLogger) {
|
|
self.logger = logger
|
|
}
|
|
|
|
func start() {
|
|
manager.delegate = self
|
|
logger.log(level: "info", message: "homekit_start")
|
|
refreshData()
|
|
}
|
|
|
|
func stop() {
|
|
manager.delegate = nil
|
|
homes = []
|
|
accessories = []
|
|
logger.log(level: "info", message: "homekit_stop")
|
|
}
|
|
|
|
func refreshData() {
|
|
homes = manager.homes
|
|
accessories = manager.homes.flatMap { $0.accessories }
|
|
logger.log(level: "info", message: "homekit_refresh", metadata: [
|
|
"homes": String(homes.count),
|
|
"accessories": String(accessories.count)
|
|
])
|
|
}
|
|
|
|
var scenes: [HMActionSet] {
|
|
manager.homes.flatMap { $0.actionSets }
|
|
}
|
|
|
|
func scene(with idString: String) -> (HMHome, HMActionSet)? {
|
|
guard let id = UUID(uuidString: idString) else { return nil }
|
|
for home in manager.homes {
|
|
if let scene = home.actionSets.first(where: { $0.uniqueIdentifier == id }) {
|
|
return (home, scene)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func executeScene(_ home: HMHome, actionSet: HMActionSet) async throws {
|
|
try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, Error>) in
|
|
home.executeActionSet(actionSet) { error in
|
|
if let error = error {
|
|
continuation.resume(throwing: error)
|
|
} else {
|
|
continuation.resume()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func characteristic(with id: UUID) -> HMCharacteristic? {
|
|
for home in manager.homes {
|
|
for accessory in home.accessories {
|
|
for service in accessory.services {
|
|
if let match = service.characteristics.first(where: { $0.uniqueIdentifier == id }) {
|
|
return match
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func characteristic(with idString: String) -> HMCharacteristic? {
|
|
guard let id = UUID(uuidString: idString) else { return nil }
|
|
return characteristic(with: id)
|
|
}
|
|
}
|
|
|
|
@MainActor
|
|
extension HomeKitManager: @preconcurrency HMHomeManagerDelegate {
|
|
func homeManagerDidUpdateHomes(_ manager: HMHomeManager) {
|
|
logger.log(level: "info", message: "homekit_homes_updated")
|
|
refreshData()
|
|
}
|
|
|
|
func homeManager(_ manager: HMHomeManager, didUpdate status: HMHomeManagerAuthorizationStatus) {
|
|
logger.log(level: "info", message: "homekit_auth_status", metadata: [
|
|
"status": String(status.rawValue)
|
|
])
|
|
refreshData()
|
|
}
|
|
}
|