49 lines
2.0 KiB
C#
49 lines
2.0 KiB
C#
using Evergreen.Health.Application.Health.Integrations.HomeAssistant;
|
|
using Evergreen.Health.Application.Health.Scenes;
|
|
using Evergreen.Health.Application.Health.Sleep;
|
|
using Microsoft.Extensions.Options;
|
|
|
|
namespace Evergreen.Health.Application.Health.Devices.Curtain;
|
|
|
|
public sealed class BedPresenceCurtainCloseAction(CurtainModule curtain, DeviceActionRunner runner,
|
|
IOptions<HomeAssistantOptions> options) : IBedPresenceAction
|
|
{
|
|
public string Key => "curtain-close";
|
|
public string Description => "关闭窗帘";
|
|
public TimeSpan ExecutionTimeout => TimeSpan.FromSeconds(55);
|
|
|
|
public bool SupportsTarget(string entityId) => options.Value.Enabled &&
|
|
entityId?.StartsWith("cover.", StringComparison.Ordinal) == true && entityId == curtain.PrimaryEntityId;
|
|
|
|
public async Task<string> ExecuteAsync(string entityId, CancellationToken token)
|
|
{
|
|
if (!SupportsTarget(entityId)) return "target-not-configured";
|
|
var state = await runner.ReadAvailableStateAsync(entityId, token);
|
|
if (state.State == "closed") return "already-closed";
|
|
if (state.State == "closing") return "already-closing";
|
|
if (state.State != "open") return "state-not-open";
|
|
|
|
var close = curtain.BuildParameterCommand("curtain_action", "close");
|
|
var command = close with
|
|
{
|
|
ExpectedState = "closed",
|
|
ValidateCurrentState = current =>
|
|
{
|
|
close.ValidateCurrentState?.Invoke(current);
|
|
if (current.State != "open") throw new InvalidOperationException("窗帘状态已改变,跳过关帘");
|
|
}
|
|
};
|
|
await runner.SendAsync(command, token);
|
|
try
|
|
{
|
|
// 机械行程需要较长回读时间。沿用窗帘命令的只读回读配置,失败不重发关帘。
|
|
await runner.VerifyParameterAsync(command, token, verificationAttempts: 20);
|
|
return "readback-confirmed";
|
|
}
|
|
catch (InvalidOperationException)
|
|
{
|
|
return "sent-readback-unconfirmed";
|
|
}
|
|
}
|
|
}
|