using Evergreen.Health.Application.Health.Devices.Environment; using Evergreen.Health.Application.Health.Entities; using Evergreen.Health.Application.Health.Integrations.HomeAssistant; using Evergreen.Health.Application.Health.Models; using Evergreen.Health.Application.Health.Policies; using Microsoft.Extensions.Options; namespace Evergreen.Health.Application.Health.Services; /// 依据室温与体质提供空调建议,不负责发送家具控制命令。 public sealed class EnvironmentAdviceService : ITransient { private readonly IHomeAssistantGateway _gateway; private readonly IndoorEnvironmentReader _environment; private readonly HomeAssistantEntityOptions _entities; public EnvironmentAdviceService(IHomeAssistantGateway gateway, IndoorEnvironmentReader environment, IOptions options) => (_gateway, _environment, _entities) = (gateway, environment, options.Value.Entities); public async Task GetAsync(HealthProfile? profile, CancellationToken cancellationToken = default) { IReadOnlyDictionary states; try { states = (await _gateway.GetStatesAsync(cancellationToken)).GroupBy(state => state.EntityId, StringComparer.OrdinalIgnoreCase) .ToDictionary(group => group.Key, group => group.Last(), StringComparer.OrdinalIgnoreCase); } catch (Exception exception) when (exception is not OperationCanceledException) { states = new Dictionary(); } return Get(profile, states); } public EnvironmentAdviceOutput Get(HealthProfile? profile, IReadOnlyDictionary states) { var tcm = TcmConstitutionRules.Read(profile); var sample = _environment.Read(states); var advice = RoomTemperaturePolicy.Evaluate(sample, RecommendedRoomRange.ForConstitution(tcm.ConstitutionCode)); advice.PendingIntegration = (advice.Mode is "heat" or "cool") && string.IsNullOrWhiteSpace(_entities.Climate); return new() { IndoorTemperatureCelsius = sample.Celsius, IndoorTemperatureAvailable = sample.Available, IndoorTemperatureObservedAt = sample.ObservedAt, ClimateAdvice = advice }; } public static void ApplyTo(PersonalizedSceneConfig config, EnvironmentAdviceOutput recommendation) { config.ClimateAdvice = recommendation.ClimateAdvice; } }