using Evergreen.Health.Application.Health.Devices.Contracts; using Evergreen.Health.Application.Health.Models; using Evergreen.Health.Application.Health.Scenes; namespace Evergreen.Health.Application.Health.Devices; public abstract class HealthDeviceModule : IHealthDeviceModule { protected DeviceActionRunner Runner { get; } protected HealthDeviceModule(DeviceActionRunner runner) => Runner = runner; public abstract string Key { get; } public abstract string Category { get; } public abstract string DisplayName { get; } public abstract string PrimaryEntityId { get; } public virtual bool PowerUsesIndependentGateway => false; public virtual bool ParameterUsesIndependentGateway(DeviceCommand command) => false; public abstract IReadOnlyList Parameters { get; } public virtual IEnumerable EntityIds => Parameters.Select(parameter => parameter.EntityId) .Append(PrimaryEntityId).Where(id => !string.IsNullOrWhiteSpace(id)).Distinct(StringComparer.OrdinalIgnoreCase); public DeviceCommand BuildParameterCommand(string parameterType, object? value) => (Parameters.FirstOrDefault(parameter => string.Equals(parameter.Key, parameterType, StringComparison.OrdinalIgnoreCase)) ?? throw new InvalidOperationException($"不支持的参数类型:{parameterType}")).Build(value); public virtual async Task ExecuteParameterAsync(DeviceCommand command, CancellationToken cancellationToken) { await Runner.SendAsync(command, cancellationToken); if (command.ExpectedState is not null) await Runner.VerifyParameterAsync(command, cancellationToken); } public virtual Task SetPowerAsync(bool turnOn, CancellationToken cancellationToken) { var domain = PrimaryEntityId.Split('.')[0]; if (domain is not ("switch" or "humidifier" or "light" or "media_player" or "climate")) throw new InvalidOperationException("该模块没有安全的主控开关"); return Runner.SendAsync(new(turnOn ? "开启设备" : "关闭设备", PrimaryEntityId, domain, turnOn ? "turn_on" : "turn_off"), cancellationToken); } public virtual Task ExecuteSleepAsync(DeviceSceneContext context, PersonalizedSceneConfig config, string constitutionCode, CancellationToken cancellationToken) => Task.CompletedTask; public virtual IEnumerable GetShutdownCommands() => []; public virtual HomeAssistantScenePresetItem? BuildPreview(PersonalizedSceneConfig config, string constitutionCode) => null; protected HomeAssistantScenePresetItem Preview(string action, string detail, Dictionary? parameters = null) => new() { DeviceName = DisplayName, Category = Category, EntityId = PrimaryEntityId, Action = action, Detail = detail, Parameters = parameters ?? new() }; }