Skip to content

Commit

Permalink
Fix "button" domain not working on CarPlay quick access (#3342)
Browse files Browse the repository at this point in the history
  • Loading branch information
bgoncal authored Jan 17, 2025
1 parent 73ca010 commit 6952af2
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 50 deletions.
37 changes: 3 additions & 34 deletions Sources/CarPlay/Templates/HAEntity+CarPlay.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,41 +32,10 @@ extension HAEntity {
}

func onPress(for api: HomeAssistantAPI) -> Promise<Void> {
var request: HATypedRequest<HAResponseVoid>?
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
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -146,26 +150,27 @@ 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 {
Current.Log.error("Failed to get server for magic item id: \(magicItem.id)")
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)
}
}
Expand Down
48 changes: 39 additions & 9 deletions Sources/Shared/API/HAAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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<Void> in
switch item.type {
Expand Down Expand Up @@ -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)
Expand All @@ -824,6 +822,38 @@ public class HomeAssistantAPI {
}
}

public func executeActionForDomainType(domain: Domain, entityId: String, state: String) -> Promise<Void> {
var request: HATypedRequest<HAResponseVoid>?
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<Void> {
firstly {
Current.sensors.sensors(reason: .registration, server: server).map(\.sensors)
Expand Down

0 comments on commit 6952af2

Please sign in to comment.