111
This commit is contained in:
@@ -109,6 +109,7 @@ public sealed class HomeAssistantDeviceSwitchOutput
|
|||||||
public string DeviceId { get; set; } = string.Empty;
|
public string DeviceId { get; set; } = string.Empty;
|
||||||
public string EntityId { get; set; } = string.Empty;
|
public string EntityId { get; set; } = string.Empty;
|
||||||
public string State { get; set; } = string.Empty;
|
public string State { get; set; } = string.Empty;
|
||||||
|
public bool? IsMuted { get; set; }
|
||||||
public string Message { get; set; } = string.Empty;
|
public string Message { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -172,30 +172,86 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
var service = input.TurnOn ? "turn_on" : "turn_off";
|
var targetOn = input.TurnOn;
|
||||||
|
bool? targetMuted = null;
|
||||||
|
var service = targetOn ? "turn_on" : "turn_off";
|
||||||
if (domain == "media_player")
|
if (domain == "media_player")
|
||||||
{
|
{
|
||||||
service = input.TurnOn ? "media_play" : "media_pause";
|
// Xiaomi Sound Pro 的 media_player state 会长期保持 playing,不能用它
|
||||||
|
// 判断声音是否开启;is_volume_muted 才是该实体可稳定回读的控制状态。
|
||||||
|
var currentMutedText = currentState.GetStringAttribute("is_volume_muted");
|
||||||
|
var currentMuted = bool.TryParse(currentMutedText, out var parsedMuted) && parsedMuted;
|
||||||
|
targetMuted = !currentMuted;
|
||||||
|
targetOn = !targetMuted.Value;
|
||||||
|
service = "volume_mute";
|
||||||
}
|
}
|
||||||
|
|
||||||
var serviceData = new Dictionary<string, object?>
|
var serviceData = new Dictionary<string, object?>
|
||||||
{
|
{
|
||||||
["entity_id"] = targetEntityId
|
["entity_id"] = targetEntityId
|
||||||
};
|
};
|
||||||
|
if (targetMuted.HasValue)
|
||||||
|
{
|
||||||
|
serviceData["is_volume_muted"] = targetMuted.Value;
|
||||||
|
}
|
||||||
|
|
||||||
await _homeAssistant.CallServiceAsync(domain, service, serviceData, cancellationToken);
|
await _homeAssistant.CallServiceAsync(domain, service, serviceData, cancellationToken);
|
||||||
|
|
||||||
|
var resultState = domain == "media_player"
|
||||||
|
? currentState.State
|
||||||
|
: (targetOn ? "on" : "off");
|
||||||
|
bool? resultMuted = null;
|
||||||
|
|
||||||
|
if (domain == "media_player")
|
||||||
|
{
|
||||||
|
var stateConfirmed = false;
|
||||||
|
for (var attempt = 0; attempt < 5; attempt++)
|
||||||
|
{
|
||||||
|
await Task.Delay(300, cancellationToken);
|
||||||
|
var refreshedStates = await _homeAssistant.GetStatesAsync(cancellationToken);
|
||||||
|
var refreshedState = refreshedStates.FirstOrDefault(s =>
|
||||||
|
string.Equals(s.EntityId, targetEntityId, StringComparison.OrdinalIgnoreCase));
|
||||||
|
if (refreshedState is null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
resultState = refreshedState.State;
|
||||||
|
var refreshedMutedText = refreshedState.GetStringAttribute("is_volume_muted");
|
||||||
|
resultMuted = bool.TryParse(refreshedMutedText, out var refreshedMuted)
|
||||||
|
? refreshedMuted
|
||||||
|
: null;
|
||||||
|
stateConfirmed = resultMuted == targetMuted;
|
||||||
|
if (stateConfirmed)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stateConfirmed)
|
||||||
|
{
|
||||||
|
return new HomeAssistantDeviceSwitchOutput
|
||||||
|
{
|
||||||
|
Success = false,
|
||||||
|
DeviceId = input.DeviceId,
|
||||||
|
EntityId = targetEntityId,
|
||||||
|
State = resultState,
|
||||||
|
IsMuted = resultMuted,
|
||||||
|
Message = $"音箱指令已发送,但静音状态未确认更新(当前:{(resultMuted.HasValue ? (resultMuted.Value ? "已静音" : "声音开启") : "未知")})"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new HomeAssistantDeviceSwitchOutput
|
return new HomeAssistantDeviceSwitchOutput
|
||||||
{
|
{
|
||||||
Success = true,
|
Success = true,
|
||||||
DeviceId = input.DeviceId,
|
DeviceId = input.DeviceId,
|
||||||
EntityId = targetEntityId,
|
EntityId = targetEntityId,
|
||||||
State = domain == "media_player"
|
State = resultState,
|
||||||
? (input.TurnOn ? "playing" : "paused")
|
IsMuted = resultMuted,
|
||||||
: (input.TurnOn ? "on" : "off"),
|
|
||||||
Message = domain == "media_player"
|
Message = domain == "media_player"
|
||||||
? $"已成功{(input.TurnOn ? "开始播放" : "暂停播放")}"
|
? (targetMuted == true ? "音箱已静音" : "音箱声音已开启")
|
||||||
: $"已成功{(input.TurnOn ? "开启" : "关闭")}设备"
|
: $"已成功{(targetOn ? "开启" : "关闭")}设备"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -384,12 +440,21 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var successMessage = parameterType switch
|
||||||
|
{
|
||||||
|
"mattress_left_mode" when !string.Equals(serviceData["option"]?.ToString(), "无", StringComparison.Ordinal) =>
|
||||||
|
"左侧承托模式已启动;床垫共用气泵,右侧会自动停止",
|
||||||
|
"mattress_right_mode" when !string.Equals(serviceData["option"]?.ToString(), "无", StringComparison.Ordinal) =>
|
||||||
|
"右侧承托模式已启动;床垫共用气泵,左侧会自动停止",
|
||||||
|
_ => "参数调节成功"
|
||||||
|
};
|
||||||
|
|
||||||
return new HomeAssistantSetParameterOutput
|
return new HomeAssistantSetParameterOutput
|
||||||
{
|
{
|
||||||
Success = true,
|
Success = true,
|
||||||
DeviceId = input.DeviceId,
|
DeviceId = input.DeviceId,
|
||||||
ParameterType = input.ParameterType ?? "",
|
ParameterType = input.ParameterType ?? "",
|
||||||
Message = "参数调节成功"
|
Message = successMessage
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -539,13 +604,17 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
|||||||
if (enableSpeakerSleepMode)
|
if (enableSpeakerSleepMode)
|
||||||
{
|
{
|
||||||
await RunAction(states, results, "开启音箱睡眠模式", entities.SpeakerSleepMode, "switch", "turn_on", null, cancellationToken);
|
await RunAction(states, results, "开启音箱睡眠模式", entities.SpeakerSleepMode, "switch", "turn_on", null, cancellationToken);
|
||||||
await RunAction(states, results, "设置助眠音量", entities.Speaker, "media_player", "volume_set",
|
|
||||||
new Dictionary<string, object?> { ["volume_level"] = speakerVolume / 100d }, cancellationToken);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await RunAction(states, results, "关闭音箱睡眠模式", entities.SpeakerSleepMode, "switch", "turn_off", null, cancellationToken);
|
await RunAction(states, results, "关闭音箱睡眠模式", entities.SpeakerSleepMode, "switch", "turn_off", null, cancellationToken);
|
||||||
}
|
}
|
||||||
|
// 音箱声音与睡眠模式是两种不同能力。即使用户未启用睡眠模式,
|
||||||
|
// 一键舒睡也应取消静音并应用个性化音量。
|
||||||
|
await RunAction(states, results, "开启音箱声音", entities.Speaker, "media_player", "volume_mute",
|
||||||
|
new Dictionary<string, object?> { ["is_volume_muted"] = false }, cancellationToken);
|
||||||
|
await RunAction(states, results, "设置助眠音量", entities.Speaker, "media_player", "volume_set",
|
||||||
|
new Dictionary<string, object?> { ["volume_level"] = speakerVolume / 100d }, cancellationToken);
|
||||||
|
|
||||||
if (scene.EnableMattress)
|
if (scene.EnableMattress)
|
||||||
{
|
{
|
||||||
@@ -571,6 +640,8 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
|||||||
await RunAction(states, results, "关闭香氛灯", entities.FragranceLight, "light", "turn_off", null, cancellationToken);
|
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.AmbientLight, "light", "turn_off", null, cancellationToken);
|
||||||
await RunAction(states, results, "关闭音箱睡眠模式", entities.SpeakerSleepMode, "switch", "turn_off", null, cancellationToken);
|
await RunAction(states, results, "关闭音箱睡眠模式", entities.SpeakerSleepMode, "switch", "turn_off", null, cancellationToken);
|
||||||
|
await RunAction(states, results, "静音音箱", entities.Speaker, "media_player", "volume_mute",
|
||||||
|
new Dictionary<string, object?> { ["is_volume_muted"] = true }, cancellationToken);
|
||||||
if (_options.SleepScene.EnableMattress)
|
if (_options.SleepScene.EnableMattress)
|
||||||
{
|
{
|
||||||
await RunAction(states, results, "关闭床垫左侧加热", entities.MattressLeftHeatingLevel, "number", "set_value",
|
await RunAction(states, results, "关闭床垫左侧加热", entities.MattressLeftHeatingLevel, "number", "set_value",
|
||||||
@@ -835,7 +906,9 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
|||||||
sceneEntityIds.Add(entities.FragranceSwitch);
|
sceneEntityIds.Add(entities.FragranceSwitch);
|
||||||
if (!string.IsNullOrWhiteSpace(entities.AmbientLight))
|
if (!string.IsNullOrWhiteSpace(entities.AmbientLight))
|
||||||
sceneEntityIds.Add(entities.AmbientLight);
|
sceneEntityIds.Add(entities.AmbientLight);
|
||||||
if (_options.SleepScene.EnableSpeakerSleepMode && !string.IsNullOrWhiteSpace(entities.SpeakerSleepMode))
|
if (!string.IsNullOrWhiteSpace(entities.Speaker))
|
||||||
|
sceneEntityIds.Add(entities.Speaker);
|
||||||
|
else if (_options.SleepScene.EnableSpeakerSleepMode && !string.IsNullOrWhiteSpace(entities.SpeakerSleepMode))
|
||||||
sceneEntityIds.Add(entities.SpeakerSleepMode);
|
sceneEntityIds.Add(entities.SpeakerSleepMode);
|
||||||
if (_options.SleepScene.EnableMattress && !string.IsNullOrWhiteSpace(entities.MattressLeftHeatingLevel))
|
if (_options.SleepScene.EnableMattress && !string.IsNullOrWhiteSpace(entities.MattressLeftHeatingLevel))
|
||||||
sceneEntityIds.Add(entities.MattressLeftHeatingLevel);
|
sceneEntityIds.Add(entities.MattressLeftHeatingLevel);
|
||||||
@@ -1114,17 +1187,17 @@ public sealed class HealthHomeAssistantService : IDynamicApiController, ITransie
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enableSpeaker && !string.IsNullOrWhiteSpace(_options.Entities.SpeakerSleepMode))
|
if (!string.IsNullOrWhiteSpace(_options.Entities.Speaker))
|
||||||
{
|
{
|
||||||
var vol = userConfig?.SpeakerVolumePercent ?? 15;
|
var vol = userConfig?.SpeakerVolumePercent ?? 15;
|
||||||
presets.Add(new HomeAssistantScenePresetItem
|
presets.Add(new HomeAssistantScenePresetItem
|
||||||
{
|
{
|
||||||
DeviceName = "Xiaomi Sound Pro",
|
DeviceName = "Xiaomi Sound Pro",
|
||||||
Category = nameof(HealthDeviceCategory.Media),
|
Category = nameof(HealthDeviceCategory.Media),
|
||||||
EntityId = _options.Entities.SpeakerSleepMode,
|
EntityId = _options.Entities.Speaker,
|
||||||
Action = "开启音箱睡眠模式",
|
Action = enableSpeaker ? "开启音箱声音和睡眠模式" : "开启音箱声音",
|
||||||
Detail = $"切换睡眠模式开关 · 音量 {vol}%",
|
Detail = enableSpeaker ? $"取消静音 · 开启睡眠模式 · 音量 {vol}%" : $"取消静音 · 音量 {vol}%",
|
||||||
Parameters = new() { ["sleep_mode"] = "开启", ["volume"] = $"{vol}%" }
|
Parameters = new() { ["muted"] = false, ["sleep_mode"] = enableSpeaker ? "开启" : "关闭", ["volume"] = $"{vol}%" }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user