using Evergreen.Health.Application.Health.Devices.Contracts; using Evergreen.Health.Application.Health.Integrations.HomeAssistant; using Evergreen.Health.Application.Health.Models; using Evergreen.Health.Application.Health.Scenes; using Microsoft.Extensions.Options; namespace Evergreen.Health.Application.Health.Devices.Lighting; public sealed class LightingModule : HealthDeviceModule { private readonly HomeAssistantEntityOptions _entities; private readonly ILightTransitionRuntime _transition; private readonly LightOffDispatcher _lightOff; public LightingModule(DeviceActionRunner runner, IOptions options, ILightTransitionRuntime transition, LightOffDispatcher lightOff) : base(runner) { _entities = options.Value.Entities; _transition = transition; _lightOff = lightOff; Parameters = [ new("brightness", PrimaryEntityId, value => { var brightness = DeviceValues.Integer(value, 0, 100, "灯光亮度"); return new("设置灯光亮度", PrimaryEntityId, "light", brightness == 0 ? "turn_off" : "turn_on", brightness == 0 ? null : new Dictionary { ["brightness_pct"] = brightness }) { Intent = brightness == 0 ? DeviceCommandIntent.TurnRelaxationLightOff : DeviceCommandIntent.TurnRelaxationLightOn }; }, "灯光亮度", 0, 100), new("color_temp", PrimaryEntityId, value => new("设置灯光色温", PrimaryEntityId, "light", "turn_on", new Dictionary { ["color_temp_kelvin"] = DeviceValues.Integer(value, 2200, 5000, "灯光色温") }) { Intent = DeviceCommandIntent.TurnRelaxationLightOn }, "灯光色温", 2200, 5000) ]; } public override string Key => "lighting"; public override string Category => nameof(HealthDeviceCategory.Lighting); public override string DisplayName => "卧室灯光"; public override string PrimaryEntityId => _entities.AmbientLight; public override IReadOnlyList Parameters { get; } public override async Task ExecuteParameterAsync(DeviceCommand command, CancellationToken cancellationToken) { // 标准手动面板复用本灯的专属安全钩子;其他灯不会触发主灯关灯事件。 command = command with { Intent = command.Service == "turn_off" ? DeviceCommandIntent.TurnRelaxationLightOff : DeviceCommandIntent.TurnRelaxationLightOn }; await _transition.CancelAsync(cancellationToken); await Runner.SendAsync(command, cancellationToken); if (command.Service == "turn_off") await _lightOff.NotifyAsync(cancellationToken); if (command.ExpectedState is not null) await Runner.VerifyParameterAsync(command, cancellationToken); } public override async Task SetPowerAsync(bool turnOn, CancellationToken cancellationToken) { if (turnOn) { await _transition.StartSleepAsync(2700, cancellationToken); return; } await _transition.CancelAsync(cancellationToken); await Runner.SendAsync(new("关闭助眠灯光", PrimaryEntityId, "light", "turn_off") { Intent = DeviceCommandIntent.TurnRelaxationLightOff }, cancellationToken); await _lightOff.NotifyAsync(cancellationToken); } public override async Task ExecuteSleepAsync(DeviceSceneContext context, PersonalizedSceneConfig config, string constitutionCode, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(PrimaryEntityId) || !context.States.TryGetValue(PrimaryEntityId, out var state) || !DeviceActionRunner.IsAvailable(state)) { context.Results.Add(new() { Name = "开启助眠渐暗灯光", EntityId = PrimaryEntityId, Status = "Skipped", Message = "灯光未配置或离线" }); return; } await context.ExternalAsync("开启助眠渐暗灯光", PrimaryEntityId, async token => { await _transition.StartSleepAsync(config.LightColorTemperatureKelvin, token); }, cancellationToken); } public override IEnumerable GetShutdownCommands() => [new("关闭助眠灯光", PrimaryEntityId, "light", "turn_off", ExpectedState: "off") { Intent = DeviceCommandIntent.TurnRelaxationLightOff }]; public override HomeAssistantScenePresetItem? BuildPreview(PersonalizedSceneConfig config, string constitutionCode) => string.IsNullOrWhiteSpace(PrimaryEntityId) ? null : Preview("开启助眠渐暗灯光", $"从50%开始,每5秒降低1%,最终关灯 · 色温 {config.LightColorTemperatureKelvin}K", new() { ["brightness"] = "50%→关闭", ["color_temp"] = $"{config.LightColorTemperatureKelvin}K" }); }