111
This commit is contained in:
@@ -22,6 +22,10 @@ public sealed class HomeAssistantEntityOptions
|
||||
public string AmbientLight { get; set; } = string.Empty;
|
||||
public string Speaker { get; set; } = string.Empty;
|
||||
public string SpeakerSleepMode { get; set; } = string.Empty;
|
||||
public string MattressLeftHeatingLevel { get; set; } = string.Empty;
|
||||
public string MattressRightHeatingLevel { get; set; } = string.Empty;
|
||||
public string MattressLeftMode { get; set; } = string.Empty;
|
||||
public string MattressRightMode { get; set; } = string.Empty;
|
||||
public string Temperature { get; set; } = string.Empty;
|
||||
public string Humidity { get; set; } = string.Empty;
|
||||
public string Pm25 { get; set; } = string.Empty;
|
||||
@@ -39,5 +43,8 @@ public sealed class HomeAssistantSleepSceneOptions
|
||||
public int LightColorTemperatureKelvin { get; set; } = 2700;
|
||||
public bool EnableFragrance { get; set; } = true;
|
||||
public bool EnableSpeakerSleepMode { get; set; }
|
||||
public bool EnableMattress { get; set; }
|
||||
public int MattressHeatingLevel { get; set; } = 1;
|
||||
public string MattressMode { get; set; } = "智能适配";
|
||||
public bool EnableUv { get; set; }
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ public sealed class HomeAssistantDiscoveredDeviceOutput
|
||||
public string? AreaName { get; set; }
|
||||
public string Category { get; set; } = nameof(HealthDeviceCategory.Other);
|
||||
public bool Online { get; set; }
|
||||
public string? PrimaryControlEntityId { get; set; }
|
||||
public List<HomeAssistantEntityOutput> Entities { get; set; } = [];
|
||||
public Dictionary<string, object?> Metrics { get; set; } = [];
|
||||
}
|
||||
@@ -71,6 +72,35 @@ public sealed class HomeAssistantStatusOutput
|
||||
public List<HomeAssistantDiscoveredDeviceOutput> Devices { get; set; } = [];
|
||||
public HomeAssistantSceneDevicesSummaryOutput SceneDevices { get; set; } = new();
|
||||
public HomeAssistantEnvironmentOutput Environment { get; set; } = new();
|
||||
public List<HomeAssistantScenePresetItem> ScenePresets { get; set; } = [];
|
||||
}
|
||||
|
||||
public sealed class HomeAssistantScenePresetItem
|
||||
{
|
||||
public string DeviceName { get; set; } = string.Empty;
|
||||
public string Category { get; set; } = string.Empty;
|
||||
public string EntityId { get; set; } = string.Empty;
|
||||
public bool Available { get; set; }
|
||||
public string AvailabilityMessage { get; set; } = string.Empty;
|
||||
public string Action { get; set; } = string.Empty;
|
||||
public string Detail { get; set; } = string.Empty;
|
||||
public Dictionary<string, object?> Parameters { get; set; } = [];
|
||||
}
|
||||
|
||||
public sealed class HomeAssistantDeviceSwitchInput
|
||||
{
|
||||
public string DeviceId { get; set; } = string.Empty;
|
||||
public string? EntityId { get; set; }
|
||||
public bool TurnOn { get; set; }
|
||||
}
|
||||
|
||||
public sealed class HomeAssistantDeviceSwitchOutput
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public string DeviceId { get; set; } = string.Empty;
|
||||
public string EntityId { get; set; } = string.Empty;
|
||||
public string State { get; set; } = string.Empty;
|
||||
public string Message { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public sealed class HomeAssistantSceneOutput
|
||||
|
||||
@@ -45,9 +45,10 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
var registries = await _registryService.GetRegistriesAsync(cancellationToken);
|
||||
|
||||
var discoveredDevices = BuildDiscoveredDevices(registries, stateMap);
|
||||
var summary = BuildSummary(discoveredDevices, states);
|
||||
var summary = BuildSummary(discoveredDevices);
|
||||
var sceneDevices = BuildSceneDevicesSummary(stateMap);
|
||||
var environment = BuildEnvironmentOutput(stateMap, discoveredDevices);
|
||||
var scenePresets = BuildScenePresets(stateMap);
|
||||
|
||||
return new HomeAssistantStatusOutput
|
||||
{
|
||||
@@ -57,7 +58,8 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
Summary = summary,
|
||||
Devices = discoveredDevices,
|
||||
SceneDevices = sceneDevices,
|
||||
Environment = environment
|
||||
Environment = environment,
|
||||
ScenePresets = scenePresets
|
||||
};
|
||||
}
|
||||
catch (Exception exception)
|
||||
@@ -69,8 +71,121 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
CheckedAt = DateTimeOffset.Now,
|
||||
Summary = new HomeAssistantSummaryOutput(),
|
||||
Devices = [],
|
||||
SceneDevices = new HomeAssistantSceneDevicesSummaryOutput { Total = 4, Available = 0 },
|
||||
Environment = new HomeAssistantEnvironmentOutput()
|
||||
SceneDevices = BuildSceneDevicesSummary(new Dictionary<string, HomeAssistantState>(StringComparer.OrdinalIgnoreCase)),
|
||||
Environment = new HomeAssistantEnvironmentOutput(),
|
||||
ScenePresets = BuildScenePresets(new Dictionary<string, HomeAssistantState>(StringComparer.OrdinalIgnoreCase))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Authorize]
|
||||
[HttpPost("/api/health/home-assistant/devices/switch")]
|
||||
public async Task<HomeAssistantDeviceSwitchOutput> SwitchDevice(
|
||||
[FromBody] HomeAssistantDeviceSwitchInput input,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(input.DeviceId))
|
||||
{
|
||||
return new HomeAssistantDeviceSwitchOutput
|
||||
{
|
||||
Success = false,
|
||||
Message = "未指定控制设备"
|
||||
};
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var states = await _homeAssistant.GetStatesAsync(cancellationToken);
|
||||
var stateMap = states.ToDictionary(s => s.EntityId, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
var registries = await _registryService.GetRegistriesAsync(cancellationToken);
|
||||
var discovered = BuildDiscoveredDevices(registries, stateMap);
|
||||
var targetDevice = discovered.FirstOrDefault(d =>
|
||||
string.Equals(d.DeviceId, input.DeviceId, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (targetDevice is null || string.IsNullOrWhiteSpace(targetDevice.PrimaryControlEntityId))
|
||||
{
|
||||
return new HomeAssistantDeviceSwitchOutput
|
||||
{
|
||||
Success = false,
|
||||
DeviceId = input.DeviceId,
|
||||
Message = "该设备没有经过确认的主控开关"
|
||||
};
|
||||
}
|
||||
|
||||
var targetEntityId = targetDevice.PrimaryControlEntityId;
|
||||
if (!string.IsNullOrWhiteSpace(input.EntityId) &&
|
||||
!string.Equals(input.EntityId, targetEntityId, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return new HomeAssistantDeviceSwitchOutput
|
||||
{
|
||||
Success = false,
|
||||
DeviceId = input.DeviceId,
|
||||
EntityId = input.EntityId,
|
||||
Message = "请求的实体不属于该设备的主控能力"
|
||||
};
|
||||
}
|
||||
|
||||
var candidate = targetDevice.Entities.FirstOrDefault(e =>
|
||||
string.Equals(e.EntityId, targetEntityId, StringComparison.OrdinalIgnoreCase));
|
||||
if (candidate is null || candidate.Domain is not ("switch" or "humidifier" or "light" or "media_player" or "climate"))
|
||||
{
|
||||
return new HomeAssistantDeviceSwitchOutput
|
||||
{
|
||||
Success = false,
|
||||
DeviceId = input.DeviceId,
|
||||
EntityId = targetEntityId,
|
||||
Message = "该实体不支持安全的开关控制"
|
||||
};
|
||||
}
|
||||
|
||||
var domain = candidate.Domain;
|
||||
|
||||
if (!stateMap.TryGetValue(targetEntityId, out var currentState) || !IsAvailable(currentState))
|
||||
{
|
||||
return new HomeAssistantDeviceSwitchOutput
|
||||
{
|
||||
Success = false,
|
||||
DeviceId = input.DeviceId,
|
||||
EntityId = targetEntityId,
|
||||
Message = "目标设备当前处于离线状态"
|
||||
};
|
||||
}
|
||||
|
||||
var service = input.TurnOn ? "turn_on" : "turn_off";
|
||||
if (domain == "media_player")
|
||||
{
|
||||
service = input.TurnOn ? "media_play" : "media_pause";
|
||||
}
|
||||
|
||||
var serviceData = new Dictionary<string, object?>
|
||||
{
|
||||
["entity_id"] = targetEntityId
|
||||
};
|
||||
|
||||
await _homeAssistant.CallServiceAsync(domain, service, serviceData, cancellationToken);
|
||||
|
||||
return new HomeAssistantDeviceSwitchOutput
|
||||
{
|
||||
Success = true,
|
||||
DeviceId = input.DeviceId,
|
||||
EntityId = targetEntityId,
|
||||
State = domain == "media_player"
|
||||
? (input.TurnOn ? "playing" : "paused")
|
||||
: (input.TurnOn ? "on" : "off"),
|
||||
Message = domain == "media_player"
|
||||
? $"已成功{(input.TurnOn ? "开始播放" : "暂停播放")}"
|
||||
: $"已成功{(input.TurnOn ? "开启" : "关闭")}设备"
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new HomeAssistantDeviceSwitchOutput
|
||||
{
|
||||
Success = false,
|
||||
DeviceId = input.DeviceId,
|
||||
EntityId = input.EntityId ?? string.Empty,
|
||||
Message = $"控制失败:{ex.Message}"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -180,6 +295,18 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
|
||||
if (scene.EnableSpeakerSleepMode)
|
||||
await RunAction(states, results, "开启音箱睡眠模式", entities.SpeakerSleepMode, "switch", "turn_on", null, cancellationToken);
|
||||
|
||||
if (scene.EnableMattress)
|
||||
{
|
||||
await RunAction(states, results, "设置床垫左侧低档加热", entities.MattressLeftHeatingLevel, "number", "set_value",
|
||||
new Dictionary<string, object?> { ["value"] = scene.MattressHeatingLevel }, cancellationToken);
|
||||
await RunAction(states, results, "设置床垫右侧低档加热", entities.MattressRightHeatingLevel, "number", "set_value",
|
||||
new Dictionary<string, object?> { ["value"] = scene.MattressHeatingLevel }, cancellationToken);
|
||||
await RunAction(states, results, "设置床垫左侧智能适配", entities.MattressLeftMode, "select", "select_option",
|
||||
new Dictionary<string, object?> { ["option"] = scene.MattressMode }, cancellationToken);
|
||||
await RunAction(states, results, "设置床垫右侧智能适配", entities.MattressRightMode, "select", "select_option",
|
||||
new Dictionary<string, object?> { ["option"] = scene.MattressMode }, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ExecuteAllOffActions(
|
||||
@@ -193,6 +320,13 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
await RunAction(states, results, "关闭香氛灯", entities.FragranceLight, "light", "turn_off", null, cancellationToken);
|
||||
await RunAction(states, results, "关闭助眠灯光", entities.AmbientLight, "light", "turn_off", null, cancellationToken);
|
||||
await RunAction(states, results, "关闭音箱睡眠模式", entities.SpeakerSleepMode, "switch", "turn_off", null, cancellationToken);
|
||||
if (_options.SleepScene.EnableMattress)
|
||||
{
|
||||
await RunAction(states, results, "关闭床垫左侧加热", entities.MattressLeftHeatingLevel, "number", "set_value",
|
||||
new Dictionary<string, object?> { ["value"] = 0 }, cancellationToken);
|
||||
await RunAction(states, results, "关闭床垫右侧加热", entities.MattressRightHeatingLevel, "number", "set_value",
|
||||
new Dictionary<string, object?> { ["value"] = 0 }, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RunAction(
|
||||
@@ -263,7 +397,7 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
|| (device.Model?.Contains("xiaomi", StringComparison.OrdinalIgnoreCase) == true)
|
||||
|| regEntities.Any(e => string.Equals(e.Platform, "xiaomi_home", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (!isXiaomi && regEntities.Count == 0)
|
||||
if (!isXiaomi)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -302,10 +436,11 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
|
||||
var areaName = !string.IsNullOrWhiteSpace(device.AreaId) && areaMap.TryGetValue(device.AreaId, out var an)
|
||||
? an
|
||||
: "睡眠空间";
|
||||
: null;
|
||||
|
||||
var category = CategorizeDevice(displayName, device.Model ?? "", device.Manufacturer ?? "", entityOutputs);
|
||||
var metrics = ExtractDeviceMetrics(category, entityOutputs);
|
||||
var primaryControlEntityId = FindPrimaryControlEntityId(category, entityOutputs);
|
||||
|
||||
discovered.Add(new HomeAssistantDiscoveredDeviceOutput
|
||||
{
|
||||
@@ -316,6 +451,7 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
AreaName = areaName,
|
||||
Category = category,
|
||||
Online = isOnline,
|
||||
PrimaryControlEntityId = primaryControlEntityId,
|
||||
Entities = entityOutputs,
|
||||
Metrics = metrics
|
||||
});
|
||||
@@ -357,6 +493,7 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
|
||||
var online = entityOutputs.Any(e => e.Available);
|
||||
var metrics = ExtractDeviceMetrics(category, entityOutputs);
|
||||
var primaryControlEntityId = FindPrimaryControlEntityId(category, entityOutputs);
|
||||
|
||||
list.Add(new HomeAssistantDiscoveredDeviceOutput
|
||||
{
|
||||
@@ -367,6 +504,7 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
AreaName = area,
|
||||
Category = category,
|
||||
Online = online,
|
||||
PrimaryControlEntityId = primaryControlEntityId,
|
||||
Entities = entityOutputs,
|
||||
Metrics = metrics
|
||||
});
|
||||
@@ -388,15 +526,42 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
return list;
|
||||
}
|
||||
|
||||
private string? FindPrimaryControlEntityId(
|
||||
string category,
|
||||
IReadOnlyList<HomeAssistantEntityOutput> entities)
|
||||
{
|
||||
var configuredEntityIds = category switch
|
||||
{
|
||||
nameof(HealthDeviceCategory.EnvironmentControl) => new[] { _options.Entities.Dehumidifier },
|
||||
nameof(HealthDeviceCategory.Fragrance) => new[] { _options.Entities.FragranceSwitch },
|
||||
nameof(HealthDeviceCategory.Lighting) => new[] { _options.Entities.AmbientLight, _options.Entities.FragranceLight },
|
||||
nameof(HealthDeviceCategory.Media) => new[] { _options.Entities.Speaker },
|
||||
_ => Array.Empty<string>()
|
||||
};
|
||||
|
||||
foreach (var configuredEntityId in configuredEntityIds.Where(id => !string.IsNullOrWhiteSpace(id)))
|
||||
{
|
||||
if (entities.Any(e => string.Equals(e.EntityId, configuredEntityId, StringComparison.OrdinalIgnoreCase)))
|
||||
return configuredEntityId;
|
||||
}
|
||||
|
||||
return category switch
|
||||
{
|
||||
nameof(HealthDeviceCategory.EnvironmentControl) => entities.FirstOrDefault(e => e.Domain == "humidifier")?.EntityId,
|
||||
nameof(HealthDeviceCategory.Lighting) => entities.FirstOrDefault(e => e.Domain == "light")?.EntityId,
|
||||
nameof(HealthDeviceCategory.Media) => entities.FirstOrDefault(e => e.Domain == "media_player")?.EntityId,
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
private static HomeAssistantSummaryOutput BuildSummary(
|
||||
IReadOnlyList<HomeAssistantDiscoveredDeviceOutput> devices,
|
||||
IReadOnlyList<HomeAssistantState> states)
|
||||
IReadOnlyList<HomeAssistantDiscoveredDeviceOutput> devices)
|
||||
{
|
||||
var totalDevices = devices.Count;
|
||||
var onlineDevices = devices.Count(d => d.Online);
|
||||
var offlineDevices = totalDevices - onlineDevices;
|
||||
var totalEntities = states.Count;
|
||||
var availableEntities = states.Count(IsAvailable);
|
||||
var totalEntities = devices.Sum(d => d.Entities.Count);
|
||||
var availableEntities = devices.Sum(d => d.Entities.Count(e => e.Available));
|
||||
|
||||
return new HomeAssistantSummaryOutput
|
||||
{
|
||||
@@ -411,30 +576,27 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
private HomeAssistantSceneDevicesSummaryOutput BuildSceneDevicesSummary(IReadOnlyDictionary<string, HomeAssistantState> stateMap)
|
||||
{
|
||||
var entities = _options.Entities;
|
||||
var sceneAvailableCount = 0;
|
||||
var sceneEntityIds = new List<string>();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(entities.Dehumidifier) &&
|
||||
stateMap.TryGetValue(entities.Dehumidifier, out var sDehum) && IsAvailable(sDehum))
|
||||
sceneAvailableCount++;
|
||||
if (!string.IsNullOrWhiteSpace(entities.Dehumidifier))
|
||||
sceneEntityIds.Add(entities.Dehumidifier);
|
||||
if (_options.SleepScene.EnableFragrance && !string.IsNullOrWhiteSpace(entities.FragranceSwitch))
|
||||
sceneEntityIds.Add(entities.FragranceSwitch);
|
||||
if (!string.IsNullOrWhiteSpace(entities.AmbientLight))
|
||||
sceneEntityIds.Add(entities.AmbientLight);
|
||||
if (_options.SleepScene.EnableSpeakerSleepMode && !string.IsNullOrWhiteSpace(entities.SpeakerSleepMode))
|
||||
sceneEntityIds.Add(entities.SpeakerSleepMode);
|
||||
if (_options.SleepScene.EnableMattress && !string.IsNullOrWhiteSpace(entities.MattressLeftHeatingLevel))
|
||||
sceneEntityIds.Add(entities.MattressLeftHeatingLevel);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(entities.FragranceSwitch) &&
|
||||
stateMap.TryGetValue(entities.FragranceSwitch, out var sFrag) && IsAvailable(sFrag))
|
||||
sceneAvailableCount++;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(entities.AmbientLight) &&
|
||||
stateMap.TryGetValue(entities.AmbientLight, out var sLight) && IsAvailable(sLight))
|
||||
sceneAvailableCount++;
|
||||
|
||||
var speakerOnline = (!string.IsNullOrWhiteSpace(entities.Speaker) &&
|
||||
stateMap.TryGetValue(entities.Speaker, out var sSpk) && IsAvailable(sSpk))
|
||||
|| (!string.IsNullOrWhiteSpace(entities.SpeakerSleepMode) &&
|
||||
stateMap.TryGetValue(entities.SpeakerSleepMode, out var sSpkSleep) && IsAvailable(sSpkSleep));
|
||||
if (speakerOnline) sceneAvailableCount++;
|
||||
sceneEntityIds = sceneEntityIds.Distinct(StringComparer.OrdinalIgnoreCase).ToList();
|
||||
var sceneAvailableCount = sceneEntityIds.Count(entityId =>
|
||||
stateMap.TryGetValue(entityId, out var state) && IsAvailable(state));
|
||||
|
||||
return new HomeAssistantSceneDevicesSummaryOutput
|
||||
{
|
||||
Total = 4,
|
||||
Available = Math.Min(4, sceneAvailableCount)
|
||||
Total = sceneEntityIds.Count,
|
||||
Available = sceneAvailableCount
|
||||
};
|
||||
}
|
||||
|
||||
@@ -470,6 +632,7 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
Temperature = GetVal(entities.Temperature, "temperature"),
|
||||
Humidity = humidity,
|
||||
Pm25 = GetVal(entities.Pm25, "pm25"),
|
||||
Pm10 = GetVal(string.Empty, "pm10"),
|
||||
Co2 = GetVal(entities.Co2, "co2"),
|
||||
Hcho = GetVal(entities.Formaldehyde, "hcho"),
|
||||
Tvoc = GetVal(entities.Tvoc, "tvoc")
|
||||
@@ -570,6 +733,104 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
||||
return safe.Count > 0 ? safe : null;
|
||||
}
|
||||
|
||||
private List<HomeAssistantScenePresetItem> BuildScenePresets(
|
||||
IReadOnlyDictionary<string, HomeAssistantState> stateMap)
|
||||
{
|
||||
var scene = _options.SleepScene;
|
||||
var presets = new List<HomeAssistantScenePresetItem>();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_options.Entities.Dehumidifier))
|
||||
{
|
||||
presets.Add(new HomeAssistantScenePresetItem
|
||||
{
|
||||
DeviceName = "米家变频净化除湿机 Max",
|
||||
Category = nameof(HealthDeviceCategory.EnvironmentControl),
|
||||
EntityId = _options.Entities.Dehumidifier,
|
||||
Action = "开启恒湿舒睡",
|
||||
Detail = $"目标湿度 {scene.TargetHumidity}% · {scene.DehumidifierMode}模式 · 风速{scene.FanLevel} · UV{(scene.EnableUv ? "开" : "关")}",
|
||||
Parameters = new()
|
||||
{
|
||||
["target_humidity"] = $"{scene.TargetHumidity}%",
|
||||
["mode"] = scene.DehumidifierMode,
|
||||
["fan_level"] = scene.FanLevel,
|
||||
["uv"] = scene.EnableUv ? "开启" : "关闭"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (scene.EnableFragrance && !string.IsNullOrWhiteSpace(_options.Entities.FragranceSwitch))
|
||||
{
|
||||
presets.Add(new HomeAssistantScenePresetItem
|
||||
{
|
||||
DeviceName = "米家智能香氛机",
|
||||
Category = nameof(HealthDeviceCategory.Fragrance),
|
||||
EntityId = _options.Entities.FragranceSwitch,
|
||||
Action = "开启香氛释放",
|
||||
Detail = "开启香氛机;香氛灯可用时同步开启柔光",
|
||||
Parameters = new() { ["power"] = "开启" }
|
||||
});
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_options.Entities.AmbientLight))
|
||||
{
|
||||
presets.Add(new HomeAssistantScenePresetItem
|
||||
{
|
||||
DeviceName = "Lemesh 色温灯",
|
||||
Category = nameof(HealthDeviceCategory.Lighting),
|
||||
EntityId = _options.Entities.AmbientLight,
|
||||
Action = "开启暖光助眠",
|
||||
Detail = $"亮度 {scene.LightBrightnessPercent}% · 色温 {scene.LightColorTemperatureKelvin}K",
|
||||
Parameters = new()
|
||||
{
|
||||
["brightness"] = $"{scene.LightBrightnessPercent}%",
|
||||
["color_temp"] = $"{scene.LightColorTemperatureKelvin}K"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (scene.EnableSpeakerSleepMode && !string.IsNullOrWhiteSpace(_options.Entities.SpeakerSleepMode))
|
||||
{
|
||||
presets.Add(new HomeAssistantScenePresetItem
|
||||
{
|
||||
DeviceName = "Xiaomi Sound Pro",
|
||||
Category = nameof(HealthDeviceCategory.Media),
|
||||
EntityId = _options.Entities.SpeakerSleepMode,
|
||||
Action = "开启音箱睡眠模式",
|
||||
Detail = "仅切换已确认的睡眠模式开关,不自动播放未知媒体内容",
|
||||
Parameters = new() { ["sleep_mode"] = "开启" }
|
||||
});
|
||||
}
|
||||
|
||||
if (scene.EnableMattress && !string.IsNullOrWhiteSpace(_options.Entities.MattressLeftHeatingLevel))
|
||||
{
|
||||
presets.Add(new HomeAssistantScenePresetItem
|
||||
{
|
||||
DeviceName = "8H AI智能好睡眠床垫X",
|
||||
Category = nameof(HealthDeviceCategory.Sleep),
|
||||
EntityId = _options.Entities.MattressLeftHeatingLevel,
|
||||
Action = "开启低档加热与智能适配",
|
||||
Detail = $"左右加热 {scene.MattressHeatingLevel} 档 · 左右气袋模式 {scene.MattressMode}",
|
||||
Parameters = new()
|
||||
{
|
||||
["left_heating_level"] = scene.MattressHeatingLevel,
|
||||
["right_heating_level"] = scene.MattressHeatingLevel,
|
||||
["left_mode"] = scene.MattressMode,
|
||||
["right_mode"] = scene.MattressMode
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
foreach (var preset in presets)
|
||||
{
|
||||
preset.Available = !string.IsNullOrWhiteSpace(preset.EntityId) &&
|
||||
stateMap.TryGetValue(preset.EntityId, out var state) &&
|
||||
IsAvailable(state);
|
||||
preset.AvailabilityMessage = preset.Available ? "当前可执行" : "当前不可用,执行时跳过";
|
||||
}
|
||||
|
||||
return presets;
|
||||
}
|
||||
|
||||
private static bool IsAvailable(HomeAssistantState state)
|
||||
=> state.State is not ("unavailable" or "unknown");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user