去掉老床垫相关功能
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
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;
|
||||
|
||||
/// <summary>依据室温与体质提供空调建议,不负责发送家具控制命令。</summary>
|
||||
public sealed class EnvironmentAdviceService : ITransient
|
||||
{
|
||||
private readonly IHomeAssistantGateway _gateway;
|
||||
private readonly IndoorEnvironmentReader _environment;
|
||||
private readonly HomeAssistantEntityOptions _entities;
|
||||
public EnvironmentAdviceService(IHomeAssistantGateway gateway, IndoorEnvironmentReader environment,
|
||||
IOptions<HomeAssistantOptions> options)
|
||||
=> (_gateway, _environment, _entities) = (gateway, environment, options.Value.Entities);
|
||||
|
||||
public async Task<EnvironmentAdviceOutput> GetAsync(HealthProfile? profile, CancellationToken cancellationToken = default)
|
||||
{
|
||||
IReadOnlyDictionary<string, HomeAssistantState> 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<string, HomeAssistantState>();
|
||||
}
|
||||
return Get(profile, states);
|
||||
}
|
||||
|
||||
public EnvironmentAdviceOutput Get(HealthProfile? profile, IReadOnlyDictionary<string, HomeAssistantState> 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,7 +24,7 @@ public sealed class HealthAppService : IDynamicApiController, ITransient
|
||||
private readonly SqlSugarRepository<HealthProfile> _profileRepository;
|
||||
private readonly SqlSugarRepository<HealthModuleSelection> _moduleRepository;
|
||||
private readonly SqlSugarRepository<HealthPlan> _planRepository;
|
||||
private readonly MattressComfortService _mattressComfort;
|
||||
private readonly EnvironmentAdviceService _environmentAdvice;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
public HealthAppService(
|
||||
@@ -32,14 +32,14 @@ public sealed class HealthAppService : IDynamicApiController, ITransient
|
||||
SqlSugarRepository<HealthProfile> profileRepository,
|
||||
SqlSugarRepository<HealthModuleSelection> moduleRepository,
|
||||
SqlSugarRepository<HealthPlan> planRepository,
|
||||
MattressComfortService mattressComfort,
|
||||
EnvironmentAdviceService environmentAdvice,
|
||||
IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_userRepository = userRepository;
|
||||
_profileRepository = profileRepository;
|
||||
_moduleRepository = moduleRepository;
|
||||
_planRepository = planRepository;
|
||||
_mattressComfort = mattressComfort;
|
||||
_environmentAdvice = environmentAdvice;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
@@ -118,11 +118,11 @@ public sealed class HealthAppService : IDynamicApiController, ITransient
|
||||
}
|
||||
|
||||
var tcmResult = TcmConstitutionRules.Read(profile);
|
||||
MattressComfortOutput? mattressComfort = null;
|
||||
EnvironmentAdviceOutput? environmentAdvice = null;
|
||||
if (tcmResult.HasCompleted)
|
||||
{
|
||||
mattressComfort = await _mattressComfort.GetAsync(profile);
|
||||
MattressComfortService.ApplyTo(tcmResult.SceneConfig, mattressComfort);
|
||||
environmentAdvice = await _environmentAdvice.GetAsync(profile);
|
||||
EnvironmentAdviceService.ApplyTo(tcmResult.SceneConfig, environmentAdvice);
|
||||
}
|
||||
|
||||
return new HealthDashboardOutput
|
||||
@@ -136,7 +136,7 @@ public sealed class HealthAppService : IDynamicApiController, ITransient
|
||||
BmiStatus = bmiStatus,
|
||||
SceneConfig = tcmResult.HasCompleted ? tcmResult.SceneConfig : null,
|
||||
TcmResult = tcmResult,
|
||||
MattressComfort = mattressComfort
|
||||
EnvironmentAdvice = environmentAdvice
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
private readonly HomeAssistantOptions _options;
|
||||
private readonly SqlSugarRepository<HealthSceneExecution> _executionRepository;
|
||||
private readonly SqlSugarRepository<HealthProfile> _profileRepository;
|
||||
private readonly MattressComfortService _mattressComfort;
|
||||
private readonly EnvironmentAdviceService _environmentAdvice;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly DeviceModuleRegistry _modules;
|
||||
private readonly DeviceParameterController _parameters;
|
||||
@@ -46,7 +46,7 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
IOptions<HomeAssistantOptions> options,
|
||||
SqlSugarRepository<HealthSceneExecution> executionRepository,
|
||||
SqlSugarRepository<HealthProfile> profileRepository,
|
||||
MattressComfortService mattressComfort,
|
||||
EnvironmentAdviceService environmentAdvice,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
DeviceModuleRegistry modules,
|
||||
DeviceParameterController parameters,
|
||||
@@ -61,7 +61,7 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
_options = options.Value;
|
||||
_executionRepository = executionRepository;
|
||||
_profileRepository = profileRepository;
|
||||
_mattressComfort = mattressComfort;
|
||||
_environmentAdvice = environmentAdvice;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_modules = modules;
|
||||
_parameters = parameters;
|
||||
@@ -128,8 +128,8 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
{
|
||||
constitutionCode = tcmResult.ConstitutionCode;
|
||||
userConfig = tcmResult.SceneConfig;
|
||||
var comfort = _mattressComfort.Get(profile, stateMap);
|
||||
MattressComfortService.ApplyTo(userConfig, comfort);
|
||||
var comfort = _environmentAdvice.Get(profile, stateMap);
|
||||
EnvironmentAdviceService.ApplyTo(userConfig, comfort);
|
||||
}
|
||||
}
|
||||
catch (Exception exception) when (exception is not OperationCanceledException)
|
||||
@@ -340,8 +340,8 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
if (!tcmResult.HasCompleted)
|
||||
throw new ScenePreparationException("请先完成中医四诊,生成体质倾向后再一键启动");
|
||||
var config = tcmResult.SceneConfig;
|
||||
var mattressComfort = await _mattressComfort.GetAsync(profile, token);
|
||||
MattressComfortService.ApplyTo(config, mattressComfort);
|
||||
var environmentAdvice = await _environmentAdvice.GetAsync(profile, token);
|
||||
EnvironmentAdviceService.ApplyTo(config, environmentAdvice);
|
||||
RoomTemperaturePolicy.PickTargetForSession(config.ClimateAdvice);
|
||||
return new PreparedSleepScene(config, tcmResult.ConstitutionCode);
|
||||
});
|
||||
|
||||
@@ -213,8 +213,6 @@ public static class TcmConstitutionRules
|
||||
{
|
||||
TargetHumidity = humidity, DehumidifierMode = "睡眠", FanLevel = "1档",
|
||||
LightBrightnessPercent = 20, LightColorTemperatureKelvin = kelvin,
|
||||
MattressHeatingLevel = 0, MattressLeftFirmness = 0, MattressRightFirmness = 0,
|
||||
MattressMode = "智能适配",
|
||||
EnableFragrance = fragrance && input.Answers["allergy"] != "often", FragranceLevel = 1,
|
||||
EnableSpeakerSleepMode = true, SpeakerVolumePercent = 50
|
||||
}
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
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;
|
||||
|
||||
/// <summary>组合独立的 BMI 和室温策略,不负责发送家具控制命令。</summary>
|
||||
public sealed class MattressComfortService : ITransient
|
||||
{
|
||||
private readonly IHomeAssistantGateway _gateway;
|
||||
private readonly IndoorEnvironmentReader _environment;
|
||||
private readonly HomeAssistantEntityOptions _entities;
|
||||
public MattressComfortService(IHomeAssistantGateway gateway, IndoorEnvironmentReader environment,
|
||||
IOptions<HomeAssistantOptions> options)
|
||||
=> (_gateway, _environment, _entities) = (gateway, environment, options.Value.Entities);
|
||||
|
||||
public async Task<MattressComfortOutput> GetAsync(HealthProfile? profile, CancellationToken cancellationToken = default)
|
||||
{
|
||||
IReadOnlyDictionary<string, HomeAssistantState> 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<string, HomeAssistantState>();
|
||||
}
|
||||
return Get(profile, states);
|
||||
}
|
||||
|
||||
public MattressComfortOutput Get(HealthProfile? profile, IReadOnlyDictionary<string, HomeAssistantState> states)
|
||||
{
|
||||
var bmi = BmiFirmnessPolicy.Calculate(profile?.HeightCm, profile?.WeightKg);
|
||||
var firmness = BmiFirmnessPolicy.Firmness(bmi);
|
||||
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()
|
||||
{
|
||||
Bmi = bmi, Firmness = firmness, HeatingLevel = advice.Mode == "heat" ? 1 : 0,
|
||||
IndoorTemperatureCelsius = sample.Celsius, IndoorTemperatureAvailable = sample.Available,
|
||||
IndoorTemperatureObservedAt = sample.ObservedAt, HeatingReason = advice.Reason,
|
||||
WeatherReason = advice.Reason, // 旧客户端兼容字段,不再读取或依赖室外天气。
|
||||
ClimateAdvice = advice,
|
||||
FirmnessReason = firmness is null
|
||||
? "健康档案尚无有效身高和体重,暂不自动调节软硬度"
|
||||
: $"按 BMI {bmi:0.0} 给出“{firmness}”演示起点,可在设备详情手动调整"
|
||||
};
|
||||
}
|
||||
|
||||
public static void ApplyTo(PersonalizedSceneConfig config, MattressComfortOutput recommendation)
|
||||
{
|
||||
config.MattressHeatingLevel = recommendation.HeatingLevel;
|
||||
config.MattressLeftFirmness = recommendation.Firmness is null ? 0 : FirmnessLevel(recommendation.Firmness);
|
||||
config.MattressRightFirmness = config.MattressLeftFirmness;
|
||||
config.ClimateAdvice = recommendation.ClimateAdvice;
|
||||
}
|
||||
|
||||
public static int FirmnessLevel(string firmness) => firmness switch
|
||||
{
|
||||
"最软" => 1, "很软" => 2, "稍软" => 3, "稍硬" => 4, "很硬" => 5, "最硬" => 6, _ => 0
|
||||
};
|
||||
|
||||
public static string? FirmnessName(int level) => level switch
|
||||
{
|
||||
1 => "最软", 2 => "很软", 3 => "稍软", 4 => "稍硬", 5 => "很硬", 6 => "最硬", _ => null
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user