Files
Evergreen-Health/Evergreen.Health.Application/Health/Scenes/DeviceActionSafety.cs
T
2026-10-09 16:46:30 +08:00

50 lines
2.4 KiB
C#

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; }
}
/// <summary>只依赖“启动按摩”的动作意图,不知道床垫实体。防止灯灭后较晚的启动指令再开启按摩。</summary>
public sealed class LightMassageSafetyRule : IDeviceActionSafetyRule
{
private readonly IHomeAssistantGateway _gateway;
private readonly string _lightEntity;
private readonly SceneLightSafetyState _state;
public LightMassageSafetyRule(IHomeAssistantGateway gateway, IOptions<HomeAssistantOptions> 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();
}
}