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.Integrations.MiAirX; namespace Evergreen.Health.Application.Health.Devices.Audio; public sealed class AudioModule : HealthDeviceModule { private readonly HomeAssistantEntityOptions _entities; private readonly ITcmMusicRuntime _music; public AudioModule(DeviceActionRunner runner, IOptions options, ITcmMusicRuntime music) : base(runner) { _entities = options.Value.Entities; _music = music; Parameters = [ new("volume", PrimaryEntityId, value => new("设置音箱音量", PrimaryEntityId, "audio", "volume", new Dictionary { ["volume"] = DeviceValues.Integer(value, 0, 100, "音箱音量") }), "音箱音量", 0, 100), DeviceValues.Switch("speaker_sleep_mode", _entities.SpeakerSleepMode, "switch", "音箱睡眠模式") ]; } public override string Key => "audio"; public override string Category => nameof(HealthDeviceCategory.Media); public override string DisplayName => "助眠音箱"; public override string PrimaryEntityId => _entities.Speaker; public override bool PowerUsesIndependentGateway => true; public override bool ParameterUsesIndependentGateway(DeviceCommand command) => command.Domain == "audio"; public override Task SetPowerAsync(bool turnOn, CancellationToken cancellationToken) => turnOn ? _music.PlayTestMusicAsync(cancellationToken) : _music.StopMusicAsync(cancellationToken); public override IReadOnlyList Parameters { get; } public override Task ExecuteParameterAsync(DeviceCommand command, CancellationToken cancellationToken) => command.Domain == "audio" ? _music.SetManualVolumeAsync((int)command.Data!["volume"]!, cancellationToken) : base.ExecuteParameterAsync(command, cancellationToken); public override async Task ExecuteSleepAsync(DeviceSceneContext context, PersonalizedSceneConfig config, string constitutionCode, CancellationToken cancellationToken) { await context.RunAsync(BuildParameterCommand("speaker_sleep_mode", config.EnableSpeakerSleepMode), cancellationToken); await context.ExternalAsync("播放体质助眠音乐并渐弱", PrimaryEntityId, token => _music.StartForConstitutionAsync(constitutionCode, token), cancellationToken); } public override IEnumerable GetShutdownCommands() => [new("关闭音箱睡眠模式", _entities.SpeakerSleepMode, "switch", "turn_off", ExpectedState: "off")]; public override HomeAssistantScenePresetItem? BuildPreview(PersonalizedSceneConfig config, string constitutionCode) { if (string.IsNullOrWhiteSpace(PrimaryEntityId)) return null; var preview = Preview(config.EnableSpeakerSleepMode ? "播放体质音乐并开启睡眠模式" : "播放体质音乐", "体质曲目循环播放 · 音量50%每5秒降1%", new() { ["music"] = "四诊体质专属曲目", ["sleep_mode"] = config.EnableSpeakerSleepMode ? "开启" : "关闭", ["volume"] = "50%→0%" }); preview.Available = _music.HasPlayableTracks(constitutionCode); preview.AvailabilityMessage = preview.Available ? "体质音乐已配置,执行时验证音箱" : "该体质的 OSS 音乐 URL 尚未配置"; return preview; } }