diff --git a/Sources/CarPlay/Templates/HAEntity+CarPlay.swift b/Sources/CarPlay/Templates/HAEntity+CarPlay.swift index 4b1992857..ed226043b 100644 --- a/Sources/CarPlay/Templates/HAEntity+CarPlay.swift +++ b/Sources/CarPlay/Templates/HAEntity+CarPlay.swift @@ -32,41 +32,10 @@ extension HAEntity { } func onPress(for api: HomeAssistantAPI) -> Promise { - var request: HATypedRequest? - switch Domain(rawValue: domain) { - case .button: - request = .pressButton(domain: .button, entityId: entityId) - case .cover: - request = .toggleDomain(domain: .cover, entityId: entityId) - case .inputBoolean: - request = .toggleDomain(domain: .inputBoolean, entityId: entityId) - case .inputButton: - request = .pressButton(domain: .inputButton, entityId: entityId) - case .light: - request = .toggleDomain(domain: .light, entityId: entityId) - case .scene: - request = .applyScene(entityId: entityId) - case .script: - request = .runScript(entityId: entityId) - case .switch: - request = .toggleDomain(domain: .switch, entityId: entityId) - case .lock: - guard let state = Domain.State(rawValue: state) else { return .value } - switch state { - case .unlocking, .unlocked, .opening: - request = .lockLock(entityId: entityId) - case .locked, .locking: - request = .unlockLock(entityId: entityId) - default: - break - } - case .none, .sensor, .binarySensor, .zone, .person: - break - } - if let request { - return api.connection.send(request).promise - .map { _ in () } + if let domain = Domain(rawValue: domain) { + return api.executeActionForDomainType(domain: domain, entityId: entityId, state: state) } else { + Current.Log.error("Failed to parse domain for entity \(entityId)") return .value } } diff --git a/Sources/CarPlay/Templates/QuickAccess/CarPlayQuickAccessTemplate.swift b/Sources/CarPlay/Templates/QuickAccess/CarPlayQuickAccessTemplate.swift index c31a7810c..ed3242113 100644 --- a/Sources/CarPlay/Templates/QuickAccess/CarPlayQuickAccessTemplate.swift +++ b/Sources/CarPlay/Templates/QuickAccess/CarPlayQuickAccessTemplate.swift @@ -110,12 +110,16 @@ final class CarPlayQuickAccessTemplate: CarPlayTemplateProvider { let entityProvider = CarPlayEntityListItem(serverId: magicItem.serverId, entity: placeholderItem) let listItem = entityProvider.template listItem.handler = { [weak self] _, _ in - self?.itemTap(magicItem: magicItem, info: info, item: listItem) + self?.itemTap( + magicItem: magicItem, + info: info, + item: listItem, + currentItemState: placeholderItem.state + ) } entityProviders.append(entityProvider) return listItem default: - let icon = magicItem.icon(info: info).carPlayIcon(color: .init(hex: info.customization?.iconColor)) let item = CPListItem( text: info.name, @@ -146,18 +150,19 @@ final class CarPlayQuickAccessTemplate: CarPlayTemplateProvider { private func itemTap( magicItem: MagicItem, info: MagicItem.Info, - item: CPListItem + item: CPListItem, + currentItemState: String = "" ) { if info.customization?.requiresConfirmation ?? false { showConfirmationForRunningMagicItem(item: magicItem, info: info) { [weak self] in - self?.executeMagicItem(magicItem, item: item) + self?.executeMagicItem(magicItem, item: item, currentItemState: currentItemState) } } else { - executeMagicItem(magicItem, item: item) + executeMagicItem(magicItem, item: item, currentItemState: currentItemState) } } - private func executeMagicItem(_ magicItem: MagicItem, item: CPListItem) { + private func executeMagicItem(_ magicItem: MagicItem, item: CPListItem, currentItemState: String = "") { guard let server = Current.servers.all.first(where: { server in server.identifier.rawValue == magicItem.serverId }), let api = Current.api(for: server) else { @@ -165,7 +170,7 @@ final class CarPlayQuickAccessTemplate: CarPlayTemplateProvider { displayItemResultIcon(on: item, success: false) return } - api.executeMagicItem(item: magicItem) { success in + api.executeMagicItem(item: magicItem, currentItemState: currentItemState) { success in self.displayItemResultIcon(on: item, success: success) } } diff --git a/Sources/Shared/API/HAAPI.swift b/Sources/Shared/API/HAAPI.swift index f305e1734..b03448b80 100644 --- a/Sources/Shared/API/HAAPI.swift +++ b/Sources/Shared/API/HAAPI.swift @@ -778,7 +778,8 @@ public class HomeAssistantAPI { } } - public func executeMagicItem(item: MagicItem, completion: @escaping (Bool) -> Void) { + // currentItemState is used only for lock domain since it can't be toggled + public func executeMagicItem(item: MagicItem, currentItemState: String = "", completion: @escaping (Bool) -> Void) { Current.Log.verbose("Selected magic item id: \(item.id)") firstly { () -> Promise in switch item.type { @@ -807,14 +808,11 @@ public class HomeAssistantAPI { guard let domain = item.domain else { throw MagicItemError.unknownDomain } - return Current.api(for: server)?.CallService( - domain: domain.rawValue, - service: "toggle", - serviceData: [ - "entity_id": item.id, - ], - shouldLog: true - ) ?? .init(error: HomeAssistantAPI.APIError.noAPIAvailable) + return executeActionForDomainType( + domain: domain, + entityId: item.id, + state: currentItemState + ) } }.done { completion(true) @@ -824,6 +822,38 @@ public class HomeAssistantAPI { } } + public func executeActionForDomainType(domain: Domain, entityId: String, state: String) -> Promise { + var request: HATypedRequest? + switch domain { + case .button, .inputButton: + request = .pressButton(domain: domain, entityId: entityId) + case .cover, .inputBoolean, .light, .switch: + request = .toggleDomain(domain: domain, entityId: entityId) + case .scene: + request = .applyScene(entityId: entityId) + case .script: + request = .runScript(entityId: entityId) + case .lock: + guard let state = Domain.State(rawValue: state) else { return .value } + switch state { + case .unlocking, .unlocked, .opening: + request = .lockLock(entityId: entityId) + case .locked, .locking: + request = .unlockLock(entityId: entityId) + default: + break + } + case .sensor, .binarySensor, .zone, .person: + break + } + if let request { + return connection.send(request).promise + .map { _ in () } + } else { + return .value + } + } + public func registerSensors() -> Promise { firstly { Current.sensors.sensors(reason: .registration, server: server).map(\.sensors)