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

39 lines
1.7 KiB
C#

namespace Evergreen.Health.Application.Health.Sleep;
public enum BedPresence { Unknown, Empty, Occupied }
public enum SleepDataAvailability { Unconfigured, Offline, Stale, Available }
public enum ObservedSleepStage { Unknown, Awake, Light, Deep }
/// <summary>设备读数归一化入口;不凭心率、睡眠阶段 0 或未知值推断有人/无人。</summary>
public sealed record SleepObservation(string SourceId, DateTimeOffset? ObservedAt,
SleepDataAvailability Availability, BedPresence Presence,
ObservedSleepStage Stage = ObservedSleepStage.Unknown,
double? HeartRate = null, double? RespiratoryRate = null, bool? Movement = null);
public interface ISleepObservationSource
{
string Key { get; }
Task<SleepObservation> ReadAsync(CancellationToken cancellationToken);
}
/// <summary>JE01 尚未接入,不启动轮询,也不将假数据视作“无人”。</summary>
public sealed class ReservedJe01Source : ISleepObservationSource
{
public string Key => "je01";
public Task<SleepObservation> ReadAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.FromResult(new SleepObservation(Key, null, SleepDataAvailability.Unconfigured, BedPresence.Unknown));
}
}
public sealed class SleepWorkflowOptions
{
public bool Enabled { get; init; } = false;
public TimeSpan StableBedDuration { get; init; } = TimeSpan.FromSeconds(30);
public TimeSpan PostGuidanceFadeDelay { get; init; } = TimeSpan.FromSeconds(30);
public TimeSpan MaximumObservationAge { get; init; } = TimeSpan.FromMinutes(2);
public TimeSpan SameAnomalyReminderInterval { get; init; } = TimeSpan.FromMinutes(30);
public int GuidanceVolumePercent { get; init; } = 50;
}