121 lines
7.7 KiB
C#
121 lines
7.7 KiB
C#
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;
|
||
using Evergreen.Health.Application.Health.Services;
|
||
|
||
namespace Evergreen.Health.Application.Health.Devices.Mattress;
|
||
|
||
public sealed class MattressModule : HealthDeviceModule, ILightOffHandler
|
||
{
|
||
private readonly HomeAssistantOptions _options;
|
||
private HomeAssistantEntityOptions Entities => _options.Entities;
|
||
public MattressModule(DeviceActionRunner runner, IOptions<HomeAssistantOptions> options) : base(runner)
|
||
{
|
||
_options = options.Value;
|
||
var modes = new[] { "无", "瑜伽助眠", "智能适配", "智能腰托" };
|
||
var parts = new[] { "无", "背部", "腰部", "牵引", "腿部", "全身" };
|
||
var parameters = new List<DeviceParameterDefinition>
|
||
{
|
||
DeviceValues.Number("mattress_left_heating", Entities.MattressLeftHeatingLevel, 0, 4, "床垫左侧加热档位"),
|
||
DeviceValues.Number("mattress_right_heating", Entities.MattressRightHeatingLevel, 0, 4, "床垫右侧加热档位"),
|
||
DeviceValues.Select("mattress_left_mode", Entities.MattressLeftMode, modes, "床垫左侧承托模式", true),
|
||
DeviceValues.Select("mattress_right_mode", Entities.MattressRightMode, modes, "床垫右侧承托模式", true),
|
||
DeviceValues.Select("mattress_massage_left_part", Entities.MattressLeftMassagePart, parts, "左侧按摩部位",
|
||
intent: DeviceCommandIntent.StartMassage),
|
||
DeviceValues.Select("mattress_massage_right_part", Entities.MattressRightMassagePart, parts, "右侧按摩部位",
|
||
intent: DeviceCommandIntent.StartMassage),
|
||
DeviceValues.Select("mattress_massage_level", Entities.MattressMassageLevel, ["轻柔", "强劲"], "按摩力度")
|
||
};
|
||
foreach (var (zone, entityId) in Entities.MattressFirmness)
|
||
parameters.Add(DeviceValues.Select($"mattress_firmness_{zone}", entityId,
|
||
["最软", "很软", "稍软", "稍硬", "很硬", "最硬"], $"床垫{ZoneName(zone)}软硬度"));
|
||
Parameters = parameters;
|
||
}
|
||
public override string Key => "mattress";
|
||
public override string Category => nameof(HealthDeviceCategory.Sleep);
|
||
public override string DisplayName => "智能床垫";
|
||
public override string PrimaryEntityId => ""; // 床垫没有单一总开关,不能把加热实体冒充开关。
|
||
public override IReadOnlyList<DeviceParameterDefinition> Parameters { get; }
|
||
|
||
public override async Task ExecuteSleepAsync(DeviceSceneContext context, PersonalizedSceneConfig config,
|
||
string constitutionCode, CancellationToken cancellationToken)
|
||
{
|
||
if (!_options.SleepScene.EnableMattress) return;
|
||
await context.RunAsync(BuildParameterCommand("mattress_left_heating", config.MattressHeatingLevel), cancellationToken);
|
||
await context.RunAsync(BuildParameterCommand("mattress_right_heating", config.MattressHeatingLevel), cancellationToken);
|
||
var firmness = MattressComfortService.FirmnessName(config.MattressLeftFirmness);
|
||
if (firmness is null)
|
||
context.Results.Add(new() { Name = "按 BMI 调节床垫软硬度", Status = "Skipped",
|
||
Message = "健康档案缺少身高或体重,未自动修改软硬度" });
|
||
else
|
||
foreach (var zone in Entities.MattressFirmness.Keys)
|
||
await context.RunAsync(BuildParameterCommand($"mattress_firmness_{zone}", firmness), cancellationToken);
|
||
var modeCommand = BuildParameterCommand("mattress_left_mode", "智能适配");
|
||
await context.RunAsync(modeCommand, cancellationToken);
|
||
if (context.Results.Last().Status == "Succeeded")
|
||
await Runner.VerifyBatchAsync([modeCommand], context.Results, cancellationToken);
|
||
// 气泵调节结束后再启动按摩,保持真实设备所需的顺序。
|
||
await Runner.DelayAsync(TimeSpan.FromSeconds(2), cancellationToken);
|
||
await context.RunAsync(BuildParameterCommand("mattress_massage_left_part", "无"), cancellationToken);
|
||
await context.RunAsync(BuildParameterCommand("mattress_massage_level", "轻柔"), cancellationToken);
|
||
var massage = BuildParameterCommand("mattress_massage_right_part", "全身") with { ExpectedState = "全身" };
|
||
await context.RunAsync(massage, cancellationToken);
|
||
if (context.Results.Last().Status == "Succeeded")
|
||
{
|
||
await Runner.DelayAsync(TimeSpan.FromSeconds(3), cancellationToken);
|
||
await Runner.VerifyBatchAsync([massage], context.Results, cancellationToken);
|
||
}
|
||
}
|
||
|
||
public IEnumerable<DeviceCommand> MassageOffCommands() =>
|
||
[
|
||
new("关闭床垫右侧按摩", Entities.MattressRightMassagePart, "select", "select_option",
|
||
new Dictionary<string, object?> { ["option"] = "无" }, "无"),
|
||
new("关闭床垫左侧按摩", Entities.MattressLeftMassagePart, "select", "select_option",
|
||
new Dictionary<string, object?> { ["option"] = "无" }, "无")
|
||
];
|
||
|
||
public override IEnumerable<DeviceCommand> GetShutdownCommands()
|
||
{
|
||
foreach (var command in MassageOffCommands()) yield return command;
|
||
// 未参与自动启动不等于无需关闭:手动开启的加热也要随一键关闭停止。
|
||
yield return new("关闭床垫左侧加热", Entities.MattressLeftHeatingLevel, "number", "set_value",
|
||
new Dictionary<string, object?> { ["value"] = 0 }, "0");
|
||
yield return new("关闭床垫右侧加热", Entities.MattressRightHeatingLevel, "number", "set_value",
|
||
new Dictionary<string, object?> { ["value"] = 0 }, "0");
|
||
}
|
||
|
||
public async Task HandleAsync(CancellationToken cancellationToken)
|
||
{
|
||
var commands = MassageOffCommands().Where(command => !string.IsNullOrWhiteSpace(command.EntityId)).ToArray();
|
||
var results = new List<HomeAssistantActionResult>();
|
||
foreach (var command in commands)
|
||
await Runner.RunAsync(new Dictionary<string, HomeAssistantState>(), results, command, cancellationToken, false);
|
||
await Runner.VerifyBatchAsync(commands, results, cancellationToken);
|
||
if (results.Any(result => result.Status == "Failed"))
|
||
throw new InvalidOperationException("床垫按摩未确认关闭:" +
|
||
string.Join(";", results.Where(result => result.Status == "Failed").Select(result => result.Message)));
|
||
}
|
||
|
||
public override HomeAssistantScenePresetItem? BuildPreview(PersonalizedSceneConfig config, string constitutionCode)
|
||
{
|
||
if (!_options.SleepScene.EnableMattress || !EntityIds.Any()) return null;
|
||
var firmness = MattressComfortService.FirmnessName(config.MattressLeftFirmness) ?? "未自动调节";
|
||
var preview = Preview("按室温和 BMI 调节床垫并开启右侧按摩",
|
||
$"左右加热 {config.MattressHeatingLevel} 档 · 软硬度{firmness} · 右侧全身轻柔按摩",
|
||
new() { ["heating_level"] = config.MattressHeatingLevel, ["firmness"] = firmness,
|
||
["right_massage_part"] = "全身", ["massage_level"] = "轻柔" });
|
||
preview.EntityId = EntityIds.First();
|
||
return preview;
|
||
}
|
||
|
||
public static string ZoneName(string zone) => zone switch
|
||
{
|
||
"left_shoulder" => "左肩", "right_shoulder" => "右肩", "left_back" => "左背", "right_back" => "右背",
|
||
"left_waist" => "左腰", "right_waist" => "右腰", "left_lumbar" => "左腰椎", "right_lumbar" => "右腰椎",
|
||
"left_hip" => "左臀", "right_hip" => "右臀", "left_leg" => "左腿", "right_leg" => "右腿", _ => zone
|
||
};
|
||
}
|