Fix scripts execution (#3731)

This commit is contained in:
Bruno Pantaleão Gonçalves
2025-07-16 11:28:10 +02:00
committed by GitHub
parent eed0482607
commit 23edc7ce0a
16 changed files with 98 additions and 43 deletions

View File

@@ -617,8 +617,6 @@
42333ADB2D0B1771001E8408 /* EntityRegistryListForDisplay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42333ADA2D0B1771001E8408 /* EntityRegistryListForDisplay.swift */; };
42333ADC2D0B1771001E8408 /* EntityRegistryListForDisplay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42333ADA2D0B1771001E8408 /* EntityRegistryListForDisplay.swift */; };
42333ADD2D0B1771001E8408 /* EntityRegistryListForDisplay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42333ADA2D0B1771001E8408 /* EntityRegistryListForDisplay.swift */; };
4235075D2CDB756800A19902 /* HAServices.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4235075C2CDB756800A19902 /* HAServices.swift */; };
4235075E2CDB756800A19902 /* HAServices.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4235075C2CDB756800A19902 /* HAServices.swift */; };
42383F702D9576F700C745F2 /* AppTriggerSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42383F6F2D9576F700C745F2 /* AppTriggerSource.swift */; };
42383F712D9576F700C745F2 /* AppTriggerSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42383F6F2D9576F700C745F2 /* AppTriggerSource.swift */; };
4238DCA42DD1F1E300126434 /* AppSessionValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4238DCA32DD1F1E300126434 /* AppSessionValues.swift */; };
@@ -956,6 +954,9 @@
42E9AFFF2CE63944009DDA46 /* AudioOutputSensor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42E9AFFE2CE63944009DDA46 /* AudioOutputSensor.swift */; };
42E9B0002CE63944009DDA46 /* AudioOutputSensor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42E9AFFE2CE63944009DDA46 /* AudioOutputSensor.swift */; };
42EB030A2C6E4D0E00A184A6 /* WatchMagicViewRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42EB03092C6E4D0E00A184A6 /* WatchMagicViewRow.swift */; };
42EEEFE22E2791430080E973 /* Service.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42EEEFE12E2791430080E973 /* Service.swift */; };
42EEEFE32E2791430080E973 /* Service.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42EEEFE12E2791430080E973 /* Service.swift */; };
42EEEFE52E2792B20080E973 /* Service.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42EEEFE42E2792B20080E973 /* Service.test.swift */; };
42EF0ACD2D4CDC0C0088C91E /* ResetAllCustomWidgetConfirmationAppIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42EF0ACC2D4CDC0C0088C91E /* ResetAllCustomWidgetConfirmationAppIntent.swift */; };
42EF0ACE2D4CDC0C0088C91E /* ResetAllCustomWidgetConfirmationAppIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42EF0ACC2D4CDC0C0088C91E /* ResetAllCustomWidgetConfirmationAppIntent.swift */; };
42EF0AD12D4CDFF30088C91E /* UpdateWidgetItemConfirmationStateAppIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42EF0ACF2D4CDFF30088C91E /* UpdateWidgetItemConfirmationStateAppIntent.swift */; };
@@ -2094,7 +2095,6 @@
422F951E2CFDF7C5003B7514 /* HAApplicationShortcutItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HAApplicationShortcutItem.swift; sourceTree = "<group>"; };
4231797F2D54FADD0037A8A4 /* AppIntentHaptics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIntentHaptics.swift; sourceTree = "<group>"; };
42333ADA2D0B1771001E8408 /* EntityRegistryListForDisplay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntityRegistryListForDisplay.swift; sourceTree = "<group>"; };
4235075C2CDB756800A19902 /* HAServices.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HAServices.swift; sourceTree = "<group>"; };
42383F6F2D9576F700C745F2 /* AppTriggerSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppTriggerSource.swift; sourceTree = "<group>"; };
4238DCA32DD1F1E300126434 /* AppSessionValues.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSessionValues.swift; sourceTree = "<group>"; };
4239D1802C4FFB75003497FC /* WatchUserDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchUserDefaults.swift; sourceTree = "<group>"; };
@@ -2415,6 +2415,8 @@
42E95C582CA46AD50010ECE3 /* ShareActivityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareActivityView.swift; sourceTree = "<group>"; };
42E9AFFE2CE63944009DDA46 /* AudioOutputSensor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioOutputSensor.swift; sourceTree = "<group>"; };
42EB03092C6E4D0E00A184A6 /* WatchMagicViewRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchMagicViewRow.swift; sourceTree = "<group>"; };
42EEEFE12E2791430080E973 /* Service.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Service.swift; sourceTree = "<group>"; };
42EEEFE42E2792B20080E973 /* Service.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Service.test.swift; sourceTree = "<group>"; };
42EF0ACC2D4CDC0C0088C91E /* ResetAllCustomWidgetConfirmationAppIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetAllCustomWidgetConfirmationAppIntent.swift; sourceTree = "<group>"; };
42EF0ACF2D4CDFF30088C91E /* UpdateWidgetItemConfirmationStateAppIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateWidgetItemConfirmationStateAppIntent.swift; sourceTree = "<group>"; };
42EFFAEB2C8882DD002F10FC /* CarPlayConfigurationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarPlayConfigurationView.swift; sourceTree = "<group>"; };
@@ -4847,6 +4849,7 @@
isa = PBXGroup;
children = (
42CE8FAC2B46C12C00C707F9 /* Domain.swift */,
42EEEFE12E2791430080E973 /* Service.swift */,
42FDA9352DAFEA4E00111F22 /* DeviceClass.swift */,
);
path = Domain;
@@ -5761,7 +5764,6 @@
426266432C11B0070081A818 /* Watch */,
420F53E92C4E9D43003C8415 /* Widget */,
D03D891920E0A85300D4F28D /* Shared.h */,
4235075C2CDB756800A19902 /* HAServices.swift */,
4254C4C92D103ABB00245021 /* ExternalLink.swift */,
);
path = Shared;
@@ -5808,6 +5810,7 @@
11B38EDE275BE29F00205C7B /* ConnectionInfo.test.swift */,
114CBAEA2839FC2500A9BAFF /* SecurityExceptions.test.swift */,
114CBAEC283AB92D00A9BAFF /* SecTrust+TestAdditions.swift */,
42EEEFE42E2792B20080E973 /* Service.test.swift */,
);
path = Shared;
sourceTree = "<group>";
@@ -8144,7 +8147,6 @@
11AF4D23249C924B006C74C0 /* GeocoderSensor.swift in Sources */,
4264906F2C0F1CCA002155CC /* View+RoundedCorner.swift in Sources */,
11C4629224B14E6B00031902 /* XCGLogger+UNNotification.swift in Sources */,
4235075E2CDB756800A19902 /* HAServices.swift in Sources */,
1182620224F9C3F7000795C6 /* HACoreBlahObject.swift in Sources */,
B6872E672226842100C475D1 /* MobileAppRegistrationResponse.swift in Sources */,
11482AD72505CB6E00C48C58 /* HACoreAudioObjectDevice.swift in Sources */,
@@ -8187,6 +8189,7 @@
4264906C2C0F1B60002155CC /* AssistChatItem.swift in Sources */,
424151FA2CD8EF2200D7A6F9 /* MagicItem+Migration.swift in Sources */,
42070EED2BAC523F0031E96F /* AssistService.swift in Sources */,
42EEEFE22E2791430080E973 /* Service.swift in Sources */,
B6872E642226841400C475D1 /* MobileAppRegistrationRequest.swift in Sources */,
B613936A24F728F8002B8C5D /* InputOutputDeviceSensor.swift in Sources */,
11F20BFD274D5DA900DFB163 /* Server+Fakes.swift in Sources */,
@@ -8413,6 +8416,7 @@
427FEE682D9ECFD70047C00C /* PrivacyNoteView.swift in Sources */,
11BA5EC92759AC0300FC40E8 /* XCGLogger+Export.swift in Sources */,
11B38EE4275C54A200205C7B /* FireEventIntentHandler.swift in Sources */,
42EEEFE32E2791430080E973 /* Service.swift in Sources */,
1120C5842749C6350046C38B /* ServerProviding.swift in Sources */,
B6872E6022267EE800C475D1 /* HAAPI.swift in Sources */,
B62817F2221D6CF4000BA86A /* Reachability+NetworkType.swift in Sources */,
@@ -8559,7 +8563,6 @@
4278CB892D01F81B00CFAAC9 /* AppGesture.swift in Sources */,
115BC8282676F44E00452430 /* FocusSensor.swift in Sources */,
1104FCBF2532755400B8BE34 /* WatchBackgroundRefreshScheduler.swift in Sources */,
4235075D2CDB756800A19902 /* HAServices.swift in Sources */,
429821172CD0DDCD005ECD39 /* HAButtonStyles.swift in Sources */,
4206DE5A2E25055E00142E85 /* WebsiteDataStoreHandler.swift in Sources */,
11B38EE8275C54A200205C7B /* WidgetActionsIntentHandler.swift in Sources */,
@@ -8683,6 +8686,7 @@
1165707C2702BAF5003906A7 /* DiskCache.test.swift in Sources */,
11AF4D30249DCA88006C74C0 /* ConnectivitySensor.test.swift in Sources */,
11CB98C8249DE24100B05222 /* PedometerSensor.test.swift in Sources */,
42EEEFE52E2792B20080E973 /* Service.test.swift in Sources */,
118511C224B25BEB00D18F60 /* WebhookManager.test.swift in Sources */,
114CBAEB2839FC2500A9BAFF /* SecurityExceptions.test.swift in Sources */,
11CD94BB24B2D2C100BA801D /* WebhookResponseUnhandled.test.swift in Sources */,

View File

@@ -45,9 +45,7 @@ final class ScriptAppIntent: AppIntent {
continuation.resume(returning: false)
return
}
let domain = Domain.script.rawValue
let service = script.entityId.replacingOccurrences(of: "\(domain).", with: "")
api.CallService(domain: domain, service: service, serviceData: [:], triggerSource: .AppIntent)
api.turnOnScript(scriptEntityId: script.entityId, triggerSource: .AppIntent)
.pipe { [weak self] result in
switch result {
case .fulfilled:

View File

@@ -239,7 +239,7 @@ struct WidgetBasicContainerWrapperView: View {
.font(.system(size: 10).bold())
.frame(maxWidth: .infinity, alignment: .center)
.multilineTextAlignment(.center)
.padding(.bottom, Spaces.half)
.padding(.bottom, DesignSystem.Spaces.half)
.opacity(0.5)
}
}

View File

@@ -16,7 +16,7 @@ struct WidgetBasicView: View {
private let opacityWhenDisabled: CGFloat = 0.3
var body: some View {
let spacing = sizeStyle == .compressed ? .zero : Spaces.one
let spacing = sizeStyle == .compressed ? .zero : DesignSystem.Spaces.one
VStack(alignment: .leading, spacing: spacing) {
ForEach(rows, id: \.self) { column in
HStack(spacing: spacing) {
@@ -26,7 +26,7 @@ struct WidgetBasicView: View {
}
}
}
.padding([.single, .compressed].contains(sizeStyle) ? 0 : Spaces.one)
.padding([.single, .compressed].contains(sizeStyle) ? 0 : DesignSystem.Spaces.one)
}
@ViewBuilder

View File

@@ -21,9 +21,9 @@ struct CoverIntent: SetValueIntent {
return .result()
}
var service = HAServices.toggle
var service = Service.toggle.rawValue
if !toggle {
service = value ? HAServices.openCover : HAServices.closeCover
service = value ? Service.openCover.rawValue : Service.closeCover.rawValue
}
let _ = await withCheckedContinuation { continuation in

View File

@@ -21,9 +21,9 @@ struct LightIntent: SetValueIntent {
return .result()
}
var service = HAServices.toggle
var service = Service.toggle.rawValue
if !toggle {
service = value ? HAServices.turnOn : HAServices.turnOff
service = value ? Service.turnOn.rawValue : Service.turnOff.rawValue
}
let _ = await withCheckedContinuation { continuation in

View File

@@ -21,9 +21,9 @@ struct SwitchIntent: SetValueIntent {
return .result()
}
var service = HAServices.toggle
var service = Service.toggle.rawValue
if !toggle {
service = value ? HAServices.turnOn : HAServices.turnOff
service = value ? Service.turnOn.rawValue : Service.turnOff.rawValue
}
// This intent can also handle for example, input_boolean

View File

@@ -35,7 +35,7 @@ struct WidgetCustom: Widget {
private var emptyView: some View {
let url = URL(string: "\(AppConstants.deeplinkURL.absoluteString)createCustomWidget")!
return Link(destination: url.withWidgetAuthenticity()) {
VStack(spacing: Spaces.two) {
VStack(spacing: DesignSystem.Spaces.two) {
Image(systemSymbol: .squareBadgePlusFill)
.foregroundStyle(Color.haPrimary)
.font(.system(size: 55))

View File

@@ -46,7 +46,7 @@ final class SceneAppIntent: AppIntent {
}
api.CallService(
domain: Domain.scene.rawValue,
service: "turn_on",
service: Service.turnOn.rawValue,
serviceData: ["entity_id": scene.entityId],
triggerSource: .AppIntent
)

View File

@@ -369,6 +369,12 @@ public class HomeAssistantAPI {
)
}
public func turnOnScript(scriptEntityId: String, triggerSource: AppTriggerSource) -> Promise<Void> {
CallService(domain: Domain.script.rawValue, service: Service.turnOn.rawValue, serviceData: [
"entity_id": scriptEntityId,
], triggerSource: triggerSource)
}
public func GetCameraImage(cameraEntityID: String) -> Promise<UIImage> {
Promise { seal in
guard let queryUrl = server.info.connection.activeAPIURL()?
@@ -637,7 +643,11 @@ public class HomeAssistantAPI {
actionID: String,
source: AppTriggerSource
) -> (serviceDomain: String, serviceName: String, serviceData: [String: String]) {
(serviceDomain: "scene", serviceName: "turn_on", serviceData: ["entity_id": actionID])
(
serviceDomain: Domain.scene.rawValue,
serviceName: Service.turnOn.rawValue,
serviceData: ["entity_id": actionID]
)
}
public func tagEvent(

View File

@@ -0,0 +1,13 @@
import Foundation
public enum Service: String, CaseIterable {
case turnOn = "turn_on"
case turnOff = "turn_off"
case toggle = "toggle"
case press = "press"
case lock = "lock"
case unlock = "unlock"
case open = "open"
case openCover = "open_cover"
case closeCover = "close_cover"
}

View File

@@ -1,9 +0,0 @@
import Foundation
public enum HAServices {
public static let toggle = "toggle"
public static let openCover = "open_cover"
public static let closeCover = "close_cover"
public static let turnOn = "turn_on"
public static let turnOff = "turn_off"
}

View File

@@ -10,7 +10,7 @@ public extension HATypedRequest {
type: "call_service",
data: [
"domain": domain.rawValue,
"service": "toggle",
"service": Service.toggle.rawValue,
"target": [
"entity_id": entityId,
],
@@ -24,8 +24,11 @@ public extension HATypedRequest {
HATypedRequest<HAResponseVoid>(request: .init(
type: "call_service",
data: [
"domain": "script",
"service": entityId.replacingOccurrences(of: "script.", with: ""),
"domain": Domain.script.rawValue,
"service": Service.turnOn.rawValue,
"target": [
"entity_id": entityId,
],
]
))
}
@@ -36,8 +39,8 @@ public extension HATypedRequest {
HATypedRequest<HAResponseVoid>(request: .init(
type: "call_service",
data: [
"domain": "scene",
"service": "turn_on",
"domain": Domain.scene.rawValue,
"service": Service.turnOn.rawValue,
"target": [
"entity_id": entityId,
],
@@ -53,7 +56,7 @@ public extension HATypedRequest {
type: "call_service",
data: [
"domain": domain.rawValue,
"service": "press",
"service": Service.press.rawValue,
"target": [
"entity_id": entityId,
],
@@ -67,8 +70,8 @@ public extension HATypedRequest {
HATypedRequest<HAResponseVoid>(request: .init(
type: "call_service",
data: [
"domain": "lock",
"service": "lock",
"domain": Domain.lock.rawValue,
"service": Service.lock.rawValue,
"target": [
"entity_id": entityId,
],
@@ -82,8 +85,8 @@ public extension HATypedRequest {
HATypedRequest<HAResponseVoid>(request: .init(
type: "call_service",
data: [
"domain": "lock",
"service": "unlock",
"domain": Domain.lock.rawValue,
"service": Service.unlock.rawValue,
"target": [
"entity_id": entityId,
],

View File

@@ -315,7 +315,7 @@ public extension MagicItem {
let domain = Domain.scene.rawValue
return Current.api(for: server)?.CallService(
domain: domain,
service: "turn_on",
service: Service.turnOn.rawValue,
serviceData: [
"entity_id": id,
],

View File

@@ -157,7 +157,7 @@ final class WatchCommunicatorService {
message: message,
magicItemId: itemId,
domain: .scene,
serviceName: "turn_on",
serviceName: Service.turnOn.rawValue,
serviceData: ["entity_id": itemId],
responseIdentifier: responseIdentifier
)
@@ -171,7 +171,7 @@ final class WatchCommunicatorService {
message: message,
magicItemId: itemId,
domain: domain,
serviceName: "toggle",
serviceName: Service.toggle.rawValue,
serviceData: ["entity_id": itemId],
responseIdentifier: responseIdentifier
)

View File

@@ -0,0 +1,36 @@
@testable import Shared
import Testing
struct ServiceTests {
@Test func testEnumCases() async throws {
// Test raw values
assert(Service.turnOn.rawValue == "turn_on")
assert(Service.turnOff.rawValue == "turn_off")
assert(Service.toggle.rawValue == "toggle")
assert(Service.press.rawValue == "press")
assert(Service.lock.rawValue == "lock")
assert(Service.unlock.rawValue == "unlock")
assert(Service.open.rawValue == "open")
assert(Service.openCover.rawValue == "open_cover")
assert(Service.closeCover.rawValue == "close_cover")
// Test initialization from raw value
assert(Service(rawValue: "turn_on") == .turnOn)
assert(Service(rawValue: "turn_off") == .turnOff)
assert(Service(rawValue: "toggle") == .toggle)
assert(Service(rawValue: "press") == .press)
assert(Service(rawValue: "lock") == .lock)
assert(Service(rawValue: "unlock") == .unlock)
assert(Service(rawValue: "open") == .open)
assert(Service(rawValue: "open_cover") == .openCover)
assert(Service(rawValue: "close_cover") == .closeCover)
// Test invalid raw value
assert(Service(rawValue: "invalid") == nil)
assert(
Service.allCases.count == 9,
"Wrong Service enum cases count, it currently has \(Service.allCases.count)"
)
}
}