using Evergreen.Health.Application.Health.Devices.Contracts; using Evergreen.Health.Application.Health.Integrations.HomeAssistant; using Microsoft.Extensions.Options; namespace Evergreen.Health.Application.Health.Scenes; public interface IDeviceActionSafetyRule { Task ValidateAsync(DeviceCommand command, CancellationToken cancellationToken); void Accepted(DeviceCommand command, DateTimeOffset now); } public sealed class SceneLightSafetyState { private readonly object _lock = new(); private DateTimeOffset? _offAt; public DateTimeOffset? OffAt { get { lock (_lock) return _offAt; } } public void MarkOff(DateTimeOffset now) { lock (_lock) _offAt = now; } public void MarkOn() { lock (_lock) _offAt = null; } } /// 只依赖“启动按摩”的动作意图,不知道床垫实体。防止灯灭后较晚的启动指令再开启按摩。 public sealed class LightMassageSafetyRule : IDeviceActionSafetyRule { private readonly IHomeAssistantGateway _gateway; private readonly string _lightEntity; private readonly SceneLightSafetyState _state; public LightMassageSafetyRule(IHomeAssistantGateway gateway, IOptions options, SceneLightSafetyState state) => (_gateway, _lightEntity, _state) = (gateway, options.Value.Entities.AmbientLight, state); public async Task ValidateAsync(DeviceCommand command, CancellationToken cancellationToken) { if (command.Intent != DeviceCommandIntent.StartMassage || string.IsNullOrWhiteSpace(_lightEntity)) return; var light = (await _gateway.GetStatesAsync(cancellationToken)).FirstOrDefault(item => string.Equals(item.EntityId, _lightEntity, StringComparison.OrdinalIgnoreCase)); var offAt = _state.OffAt; if (light is null || !DeviceActionRunner.IsAvailable(light) || !string.Equals(light.State, "on", StringComparison.OrdinalIgnoreCase) || light.GetDoubleAttribute("brightness") is <= 0 || (offAt is not null && (light.LastUpdated is null || light.LastUpdated <= offAt))) throw new InvalidOperationException("卧室灯光已关闭或状态未确认,不启动床垫按摩"); } public void Accepted(DeviceCommand command, DateTimeOffset now) { if (command.Intent == DeviceCommandIntent.TurnRelaxationLightOff) _state.MarkOff(now); else if (command.Intent == DeviceCommandIntent.TurnRelaxationLightOn) _state.MarkOn(); } }