111
This commit is contained in:
@@ -22,6 +22,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 IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
public HealthHomeAssistantService(
|
||||
@@ -31,6 +32,7 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
IOptions<HomeAssistantOptions> options,
|
||||
SqlSugarRepository<HealthSceneExecution> executionRepository,
|
||||
SqlSugarRepository<HealthProfile> profileRepository,
|
||||
MattressComfortService mattressComfort,
|
||||
IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_homeAssistant = homeAssistant;
|
||||
@@ -39,6 +41,7 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
_options = options.Value;
|
||||
_executionRepository = executionRepository;
|
||||
_profileRepository = profileRepository;
|
||||
_mattressComfort = mattressComfort;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
@@ -153,16 +156,21 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
var profile = await _profileRepository.GetFirstAsync(p => p.UserId == userId);
|
||||
if (!string.IsNullOrWhiteSpace(profile?.CustomSceneConfigJson))
|
||||
var tcmResult = TcmConstitutionRules.Read(profile);
|
||||
if (tcmResult.HasCompleted)
|
||||
{
|
||||
userConfig = JsonSerializer.Deserialize<PersonalizedSceneConfig>(profile.CustomSceneConfigJson);
|
||||
userConfig = tcmResult.SceneConfig;
|
||||
var comfort = await _mattressComfort.GetAsync(profile, cancellationToken);
|
||||
MattressComfortService.ApplyTo(userConfig, comfort);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
var scenePresets = BuildScenePresets(stateMap, userConfig);
|
||||
var scenePresets = userConfig is null
|
||||
? new List<HomeAssistantScenePresetItem>()
|
||||
: BuildScenePresets(stateMap, userConfig);
|
||||
|
||||
return new HomeAssistantStatusOutput
|
||||
{
|
||||
@@ -188,7 +196,7 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
Devices = [],
|
||||
SceneDevices = BuildSceneDevicesSummary(new Dictionary<string, HomeAssistantState>(StringComparer.OrdinalIgnoreCase)),
|
||||
Environment = new HomeAssistantEnvironmentOutput(),
|
||||
ScenePresets = BuildScenePresets(new Dictionary<string, HomeAssistantState>(StringComparer.OrdinalIgnoreCase)),
|
||||
ScenePresets = [],
|
||||
ControlParameters = []
|
||||
};
|
||||
}
|
||||
@@ -531,6 +539,32 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
service = "select_option";
|
||||
serviceData["option"] = ReadMattressMode(input.Value);
|
||||
break;
|
||||
case "mattress_massage_left_part":
|
||||
targetEntityId = _options.Entities.MattressLeftMassagePart;
|
||||
domain = "select";
|
||||
service = "select_option";
|
||||
serviceData["option"] = ReadMassagePart(input.Value);
|
||||
break;
|
||||
case "mattress_massage_right_part":
|
||||
targetEntityId = _options.Entities.MattressRightMassagePart;
|
||||
domain = "select";
|
||||
service = "select_option";
|
||||
serviceData["option"] = ReadMassagePart(input.Value);
|
||||
break;
|
||||
case "mattress_massage_level":
|
||||
targetEntityId = _options.Entities.MattressMassageLevel;
|
||||
domain = "select";
|
||||
service = "select_option";
|
||||
serviceData["option"] = ReadMassageLevel(input.Value);
|
||||
break;
|
||||
case string firmnessType when firmnessType.StartsWith("mattress_firmness_", StringComparison.Ordinal):
|
||||
var zone = firmnessType["mattress_firmness_".Length..];
|
||||
if (!_options.Entities.MattressFirmness.TryGetValue(zone, out targetEntityId))
|
||||
throw new InvalidOperationException("不支持该床垫分区");
|
||||
domain = "select";
|
||||
service = "select_option";
|
||||
serviceData["option"] = ReadFirmness(input.Value);
|
||||
break;
|
||||
case "uv":
|
||||
targetEntityId = _options.Entities.DehumidifierUv;
|
||||
domain = "switch";
|
||||
@@ -562,40 +596,6 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
serviceData["entity_id"] = targetEntityId;
|
||||
await _homeAssistant.CallServiceAsync(domain, service, serviceData, cancellationToken);
|
||||
|
||||
try
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
var profile = await _profileRepository.GetFirstAsync(p => p.UserId == userId);
|
||||
if (profile != null)
|
||||
{
|
||||
var customConfig = string.IsNullOrWhiteSpace(profile.CustomSceneConfigJson)
|
||||
? new PersonalizedSceneConfig()
|
||||
: JsonSerializer.Deserialize<PersonalizedSceneConfig>(profile.CustomSceneConfigJson) ?? new PersonalizedSceneConfig();
|
||||
|
||||
switch (parameterType)
|
||||
{
|
||||
case "humidity": customConfig.TargetHumidity = (int)serviceData["humidity"]!; break;
|
||||
case "fan_level": customConfig.FanLevel = (string)serviceData["option"]!; break;
|
||||
case "dehumidifier_mode": customConfig.DehumidifierMode = (string)serviceData["mode"]!; break;
|
||||
case "brightness": customConfig.LightBrightnessPercent = (int)serviceData["brightness_pct"]!; break;
|
||||
case "color_temp": customConfig.LightColorTemperatureKelvin = (int)serviceData["color_temp_kelvin"]!; break;
|
||||
case "volume": customConfig.SpeakerVolumePercent = ReadInt(input.Value, 0, 100, "音箱音量"); break;
|
||||
case "speaker_sleep_mode": customConfig.EnableSpeakerSleepMode = ReadBool(input.Value); break;
|
||||
case "uv": customConfig.EnableUv = ReadBool(input.Value); break;
|
||||
case "mattress_left_heating":
|
||||
case "mattress_right_heating": customConfig.MattressHeatingLevel = ReadInt(input.Value, 0, 4, "床垫加热档位"); break;
|
||||
case "mattress_left_mode":
|
||||
case "mattress_right_mode": customConfig.MattressMode = ReadMattressMode(input.Value); break;
|
||||
}
|
||||
|
||||
profile.CustomSceneConfigJson = JsonSerializer.Serialize(customConfig);
|
||||
await _profileRepository.UpdateAsync(profile);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
var successMessage = parameterType switch
|
||||
{
|
||||
"fragrance_quick_release" => "快速出香指令已发送",
|
||||
@@ -631,18 +631,20 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
public async Task<HomeAssistantSceneOutput> ExecuteSleepScene(CancellationToken cancellationToken)
|
||||
{
|
||||
PersonalizedSceneConfig? customConfig = null;
|
||||
try
|
||||
var userId = GetCurrentUserId();
|
||||
var profile = await _profileRepository.GetFirstAsync(p => p.UserId == userId);
|
||||
var tcmResult = TcmConstitutionRules.Read(profile);
|
||||
if (!tcmResult.HasCompleted)
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
var profile = await _profileRepository.GetFirstAsync(p => p.UserId == userId);
|
||||
if (!string.IsNullOrWhiteSpace(profile?.CustomSceneConfigJson))
|
||||
return new HomeAssistantSceneOutput
|
||||
{
|
||||
customConfig = JsonSerializer.Deserialize<PersonalizedSceneConfig>(profile.CustomSceneConfigJson);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
SceneCode = "sleep", SceneName = "舒睡模式", Success = false,
|
||||
Status = "AssessmentRequired", Message = "请先完成中医四诊,生成体质倾向后再一键启动"
|
||||
};
|
||||
}
|
||||
customConfig = tcmResult.SceneConfig;
|
||||
var mattressComfort = await _mattressComfort.GetAsync(profile, cancellationToken);
|
||||
MattressComfortService.ApplyTo(customConfig, mattressComfort);
|
||||
|
||||
return await ExecuteScene("sleep", "舒睡模式", (states, results, ct) => ExecuteSleepActions(states, results, customConfig, ct), cancellationToken);
|
||||
}
|
||||
@@ -735,7 +737,7 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
var enableSpeakerSleepMode = customConfig?.EnableSpeakerSleepMode ?? scene.EnableSpeakerSleepMode;
|
||||
var speakerVolume = customConfig?.SpeakerVolumePercent ?? 15;
|
||||
var mattressHeatingLevel = customConfig?.MattressHeatingLevel ?? scene.MattressHeatingLevel;
|
||||
var mattressMode = customConfig?.MattressMode ?? scene.MattressMode;
|
||||
var mattressFirmness = MattressComfortService.FirmnessName(customConfig?.MattressLeftFirmness ?? 0);
|
||||
|
||||
await RunAction(states, results, "开启除湿机", entities.Dehumidifier, "humidifier", "turn_on", null, cancellationToken);
|
||||
await RunAction(states, results, "设置目标湿度", entities.Dehumidifier, "humidifier", "set_humidity",
|
||||
@@ -757,6 +759,11 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
await RunAction(states, results, "开启香氛灯", entities.FragranceLight, "light", "turn_on",
|
||||
new Dictionary<string, object?> { ["brightness_pct"] = lightBrightness }, cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
await RunAction(states, results, "关闭香氛机", entities.FragranceSwitch, "switch", "turn_off", null, cancellationToken);
|
||||
await RunAction(states, results, "关闭香氛灯", entities.FragranceLight, "light", "turn_off", null, cancellationToken);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(entities.AmbientLight) ||
|
||||
!states.TryGetValue(entities.AmbientLight, out var lightState) || !IsAvailable(lightState))
|
||||
@@ -809,10 +816,24 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
new Dictionary<string, object?> { ["value"] = mattressHeatingLevel }, cancellationToken);
|
||||
await RunAction(states, results, "设置床垫右侧加热档位", entities.MattressRightHeatingLevel, "number", "set_value",
|
||||
new Dictionary<string, object?> { ["value"] = mattressHeatingLevel }, cancellationToken);
|
||||
await RunAction(states, results, "设置床垫左侧模式", entities.MattressLeftMode, "select", "select_option",
|
||||
new Dictionary<string, object?> { ["option"] = mattressMode }, cancellationToken);
|
||||
await RunAction(states, results, "设置床垫右侧模式", entities.MattressRightMode, "select", "select_option",
|
||||
new Dictionary<string, object?> { ["option"] = mattressMode }, cancellationToken);
|
||||
// 左右承托模式共用气泵,一键场景不同时启动两侧模式。
|
||||
if (mattressFirmness == null)
|
||||
{
|
||||
results.Add(new HomeAssistantActionResult
|
||||
{
|
||||
Name = "按 BMI 调节床垫软硬度", Status = "Skipped",
|
||||
Message = "健康档案缺少身高或体重,未自动修改软硬度"
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var (zone, entityId) in entities.MattressFirmness)
|
||||
{
|
||||
await RunAction(states, results, $"设置床垫{MattressZoneName(zone)}软硬度",
|
||||
entityId, "select", "select_option",
|
||||
new Dictionary<string, object?> { ["option"] = mattressFirmness }, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1268,8 +1289,13 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
["mattress_left_heating"] = _options.Entities.MattressLeftHeatingLevel,
|
||||
["mattress_right_heating"] = _options.Entities.MattressRightHeatingLevel,
|
||||
["mattress_left_mode"] = _options.Entities.MattressLeftMode,
|
||||
["mattress_right_mode"] = _options.Entities.MattressRightMode
|
||||
["mattress_right_mode"] = _options.Entities.MattressRightMode,
|
||||
["mattress_massage_left_part"] = _options.Entities.MattressLeftMassagePart,
|
||||
["mattress_massage_right_part"] = _options.Entities.MattressRightMassagePart,
|
||||
["mattress_massage_level"] = _options.Entities.MattressMassageLevel
|
||||
};
|
||||
foreach (var (zone, entityId) in _options.Entities.MattressFirmness)
|
||||
configured[$"mattress_firmness_{zone}"] = entityId;
|
||||
var result = new Dictionary<string, HomeAssistantParameterStateOutput>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var (parameterType, entityId) in configured)
|
||||
{
|
||||
@@ -1319,6 +1345,41 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
return mode;
|
||||
}
|
||||
|
||||
private static string ReadFirmness(object? value)
|
||||
{
|
||||
var firmness = ReadString(value);
|
||||
if (firmness is not ("最软" or "很软" or "稍软" or "稍硬" or "很硬" or "最硬"))
|
||||
throw new InvalidOperationException("床垫软硬度选项无效");
|
||||
return firmness;
|
||||
}
|
||||
|
||||
private static string MattressZoneName(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
|
||||
};
|
||||
|
||||
private static string ReadMassagePart(object? value)
|
||||
{
|
||||
var part = ReadString(value);
|
||||
if (part is not ("无" or "背部" or "腰部" or "牵引" or "腿部" or "全身"))
|
||||
throw new InvalidOperationException("按摩部位选项无效");
|
||||
return part;
|
||||
}
|
||||
|
||||
private static string ReadMassageLevel(object? value)
|
||||
{
|
||||
var level = ReadString(value);
|
||||
if (level is not ("轻柔" or "强劲"))
|
||||
throw new InvalidOperationException("按摩力度选项无效");
|
||||
return level;
|
||||
}
|
||||
|
||||
private List<HomeAssistantScenePresetItem> BuildScenePresets(
|
||||
IReadOnlyDictionary<string, HomeAssistantState> stateMap,
|
||||
PersonalizedSceneConfig? userConfig = null)
|
||||
@@ -1399,18 +1460,18 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
if (defaultScene.EnableMattress && !string.IsNullOrWhiteSpace(_options.Entities.MattressLeftHeatingLevel))
|
||||
{
|
||||
var heatingLevel = userConfig?.MattressHeatingLevel ?? defaultScene.MattressHeatingLevel;
|
||||
var mattressMode = userConfig?.MattressMode ?? defaultScene.MattressMode;
|
||||
var firmness = MattressComfortService.FirmnessName(userConfig?.MattressLeftFirmness ?? 0);
|
||||
presets.Add(new HomeAssistantScenePresetItem
|
||||
{
|
||||
DeviceName = "8H AI智能好睡眠床垫X",
|
||||
Category = nameof(HealthDeviceCategory.Sleep),
|
||||
EntityId = _options.Entities.MattressLeftHeatingLevel,
|
||||
Action = "开启分区加热与承托模式",
|
||||
Detail = $"左右加热 {heatingLevel} 档 · {mattressMode}",
|
||||
Action = "按天气和 BMI 调节床垫",
|
||||
Detail = $"左右加热 {heatingLevel} 档 · 软硬度{firmness ?? "待填写 BMI"}",
|
||||
Parameters = new()
|
||||
{
|
||||
["heating_level"] = heatingLevel,
|
||||
["mode"] = mattressMode
|
||||
["firmness"] = firmness ?? "未自动调节"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user