去掉老床垫相关功能
This commit is contained in:
@@ -31,7 +31,7 @@ public sealed class ClimateAdviceBindingTests
|
||||
Attributes = JsonSerializer.SerializeToElement(new { unit_of_measurement = "°C" })
|
||||
}
|
||||
};
|
||||
var service = new MattressComfortService(gateway,
|
||||
var service = new EnvironmentAdviceService(gateway,
|
||||
new IndoorEnvironmentReader(options, TimeProvider.System), options);
|
||||
var output = service.Get(null, states);
|
||||
Assert.Equal(mode, output.ClimateAdvice.Mode);
|
||||
|
||||
@@ -4,7 +4,6 @@ using Evergreen.Health.Application.Health.Devices.Contracts;
|
||||
using Evergreen.Health.Application.Health.Devices.Discovery;
|
||||
using Evergreen.Health.Application.Health.Devices.Environment;
|
||||
using Evergreen.Health.Application.Health.Devices.Lighting;
|
||||
using Evergreen.Health.Application.Health.Devices.Mattress;
|
||||
using Evergreen.Health.Application.Health.Integrations.HomeAssistant;
|
||||
using Evergreen.Health.Application.Health.Integrations.MiAirX;
|
||||
using Evergreen.Health.Application.Health.Models;
|
||||
@@ -28,11 +27,8 @@ public sealed class DeviceArchitectureTests
|
||||
Entities = new()
|
||||
{
|
||||
AmbientLight = "light.bedroom", Speaker = "media_player.speaker", SpeakerSleepMode = "switch.sleep",
|
||||
Temperature = "sensor.room_temperature", MattressLeftMode = "select.left_mode", MattressRightMode = "select.right_mode",
|
||||
MattressLeftHeatingLevel = "number.left_heat", MattressRightHeatingLevel = "number.right_heat",
|
||||
MattressLeftMassagePart = "select.left_massage", MattressRightMassagePart = "select.right_massage",
|
||||
MattressMassageLevel = "select.massage_level", MattressFirmness = new() { ["left_shoulder"] = "select.left_shoulder" }
|
||||
}, SleepScene = new() { EnableMattress = true }
|
||||
Temperature = "sensor.room_temperature"
|
||||
}
|
||||
};
|
||||
private static HomeAssistantState Temperature(double value, DateTimeOffset? observed) => new()
|
||||
{
|
||||
@@ -40,25 +36,6 @@ public sealed class DeviceArchitectureTests
|
||||
LastReported = observed, Attributes = JsonSerializer.SerializeToElement(new { unit_of_measurement = "°C" })
|
||||
};
|
||||
|
||||
[Theory]
|
||||
[InlineData(18.4, "很软")]
|
||||
[InlineData(18.5, "稍软")]
|
||||
[InlineData(24.0, "稍硬")]
|
||||
[InlineData(28.0, "很硬")]
|
||||
[InlineData(31.1, "很硬")]
|
||||
[InlineData(32.0, "最硬")]
|
||||
public void BmiUsesStableFirmnessBoundaries(double bmi, string expected)
|
||||
=> Assert.Equal(expected, BmiFirmnessPolicy.Firmness((decimal)bmi));
|
||||
|
||||
[Fact]
|
||||
public void MissingOrInvalidBodyDataNeverProducesFirmness()
|
||||
{
|
||||
Assert.Null(BmiFirmnessPolicy.Calculate(null, 80));
|
||||
Assert.Null(BmiFirmnessPolicy.Calculate(0, 80));
|
||||
Assert.Null(BmiFirmnessPolicy.Firmness(null));
|
||||
Assert.Equal(31.1m, BmiFirmnessPolicy.Calculate(180, 100.8m));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(21.9, "heat")]
|
||||
[InlineData(22.0, "off")]
|
||||
@@ -131,10 +108,6 @@ public sealed class DeviceArchitectureTests
|
||||
Assert.Throws<InvalidOperationException>(() => light.BuildParameterCommand("color_temp", 6500));
|
||||
Assert.Equal("light.bedroom", light.BuildParameterCommand("brightness", 0).EntityId);
|
||||
Assert.Equal("turn_off", light.BuildParameterCommand("brightness", 0).Service);
|
||||
var mattress = new MattressModule(runner, Options.Create(Configuration()));
|
||||
Assert.Equal("全身", mattress.BuildParameterCommand("mattress_massage_right_part", "全身").Data!["option"]);
|
||||
Assert.Equal("轻柔", mattress.BuildParameterCommand("mattress_massage_level", "轻柔").Data!["option"]);
|
||||
Assert.Throws<InvalidOperationException>(() => mattress.BuildParameterCommand("mattress_right_mode", "随意模式"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -163,15 +136,15 @@ public sealed class DeviceArchitectureTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FallbackOnlyContainsConfiguredModulesAndIncludesMattressEntities()
|
||||
public void FallbackOnlyContainsConfiguredModules()
|
||||
{
|
||||
var runner = Runner(new());
|
||||
var options = Options.Create(Configuration());
|
||||
var catalog = new HomeAssistantDeviceCatalog(options, new DeviceModuleRegistry([new MattressModule(runner, options)]));
|
||||
var catalog = new HomeAssistantDeviceCatalog(options, new DeviceModuleRegistry([new LightingModule(runner, options, new FakeLight(), new LightOffDispatcher([]))]));
|
||||
var device = Assert.Single(catalog.BuildDiscoveredDevices(null, new Dictionary<string, HomeAssistantState>()));
|
||||
Assert.Equal("mattress", device.ModuleKey);
|
||||
Assert.Contains(device.Entities, entity => entity.EntityId == "select.right_massage");
|
||||
Assert.Null(device.PrimaryControlEntityId);
|
||||
Assert.Equal("lighting", device.ModuleKey);
|
||||
Assert.Contains(device.Entities, entity => entity.EntityId == "light.bedroom");
|
||||
Assert.Equal("light.bedroom", device.PrimaryControlEntityId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -218,17 +191,15 @@ public sealed class DeviceArchitectureTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ManualLightOffUsesSceneLinkageToStopBothMassageSides()
|
||||
public async Task ManualLightOffOnlyControlsTheLight()
|
||||
{
|
||||
var gateway = new FakeHaGateway();
|
||||
var runner = Runner(gateway);
|
||||
var options = Options.Create(Configuration());
|
||||
var mattress = new MattressModule(runner, options);
|
||||
var light = new LightingModule(runner, options, new FakeLight(), new LightOffDispatcher([mattress]));
|
||||
var light = new LightingModule(runner, options, new FakeLight(), new LightOffDispatcher([]));
|
||||
await light.ExecuteParameterAsync(light.BuildParameterCommand("brightness", 0), default);
|
||||
Assert.Equal("off", gateway.States["light.bedroom"].State);
|
||||
Assert.Equal("无", gateway.States["select.right_massage"].State);
|
||||
Assert.Equal("无", gateway.States["select.left_massage"].State);
|
||||
Assert.All(gateway.Calls, command => Assert.Equal("light.bedroom", command.EntityId));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -248,7 +219,9 @@ public sealed class DeviceArchitectureTests
|
||||
using var provider = services.BuildServiceProvider(new ServiceProviderOptions { ValidateOnBuild = true, ValidateScopes = true });
|
||||
Assert.NotNull(provider.GetRequiredService<HealthSceneCoordinator>());
|
||||
Assert.Equal(2, provider.GetServices<IHostedService>().Count());
|
||||
Assert.Contains(provider.GetRequiredService<DeviceModuleRegistry>().Modules, module => module.Key == "mattress");
|
||||
Assert.DoesNotContain(provider.GetRequiredService<DeviceModuleRegistry>().Modules, module => module.Key == "mattress");
|
||||
Assert.Empty(provider.GetServices<ILightOffHandler>());
|
||||
Assert.Throws<InvalidOperationException>(() => provider.GetRequiredService<DeviceModuleRegistry>().ForParameter("mattress_left_heating"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
using Evergreen.Health.Application.Health.Devices;
|
||||
using Evergreen.Health.Application.Health.Devices.Discovery;
|
||||
using Evergreen.Health.Application.Health.Integrations.HomeAssistant;
|
||||
using Evergreen.Health.Application.Health.Scenes;
|
||||
using Evergreen.Health.Application.Health.Devices.Contracts;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Xunit;
|
||||
|
||||
namespace Admin.NET.Test.Health;
|
||||
|
||||
public sealed class RetiredDeviceTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("user")]
|
||||
public void ExplicitRetiredBindingExcludesEntireDeviceEvenWhenBindingIsDisabled(string? disabledBy)
|
||||
{
|
||||
var catalog = new HomeAssistantDeviceCatalog(Options.Create(new HomeAssistantOptions
|
||||
{
|
||||
ExcludedDeviceEntityIds = ["number.old_heat"]
|
||||
}), new DeviceModuleRegistry([]));
|
||||
var registry = new HomeAssistantRegistries
|
||||
{
|
||||
Devices = [new() { Id = "retired", Name = "智能床垫" }, new() { Id = "new", Name = "智能床垫" }],
|
||||
Entities = [new() { DeviceId = "retired", EntityId = "NUMBER.OLD_HEAT", DisabledBy = disabledBy },
|
||||
new() { DeviceId = "retired", EntityId = "switch.old" },
|
||||
new() { DeviceId = "new", EntityId = "sensor.presence" }]
|
||||
};
|
||||
var states = new Dictionary<string, HomeAssistantState>
|
||||
{
|
||||
["switch.old"] = new() { EntityId = "switch.old", State = "on" },
|
||||
["sensor.presence"] = new() { EntityId = "sensor.presence", State = "on" }
|
||||
};
|
||||
var remaining = Assert.Single(catalog.BuildDiscoveredDevices(registry, states));
|
||||
Assert.Equal("new", remaining.DeviceId);
|
||||
Assert.Equal("", remaining.ModuleKey);
|
||||
registry.Devices.RemoveAt(1);
|
||||
Assert.Empty(catalog.BuildDiscoveredDevices(registry, states));
|
||||
Assert.Empty(catalog.BuildDiscoveredDevices(null, states));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PrimaryLightCommandsStillTrackKnownOffStateWithoutMattressRules()
|
||||
{
|
||||
var state = new SceneLightSafetyState();
|
||||
var gateway = new FakeHaGateway();
|
||||
var runner = new DeviceActionRunner(gateway, TimeProvider.System, new(), [new PrimaryLightStateRule(state)]);
|
||||
await runner.SendAsync(new("关灯", "light.room", "light", "turn_off")
|
||||
{ Intent = DeviceCommandIntent.TurnRelaxationLightOff }, default);
|
||||
Assert.NotNull(state.OffAt);
|
||||
await runner.SendAsync(new("开灯", "light.room", "light", "turn_on")
|
||||
{ Intent = DeviceCommandIntent.TurnRelaxationLightOn }, default);
|
||||
Assert.Null(state.OffAt);
|
||||
Assert.All(gateway.Calls, call => Assert.Equal("light.room", call.EntityId));
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using Evergreen.Health.Application.Health.Devices;
|
||||
using Evergreen.Health.Application.Health.Devices.Contracts;
|
||||
using Evergreen.Health.Application.Health.Devices.Mattress;
|
||||
using Evergreen.Health.Application.Health.Integrations.HomeAssistant;
|
||||
using Evergreen.Health.Application.Health.Integrations.MiAirX;
|
||||
using Evergreen.Health.Application.Health.Integrations.Tuya;
|
||||
@@ -21,16 +20,13 @@ public sealed class SafetyAndReservedWorkflowTests
|
||||
SleepDataAvailability availability = SleepDataAvailability.Available) => new("fake", at, availability, presence);
|
||||
private static HomeAssistantOptions Configuration() => new()
|
||||
{
|
||||
Entities = new() { AmbientLight = "light.bedroom", MattressRightMassagePart = "select.right",
|
||||
MattressLeftMassagePart = "select.left", MattressLeftHeatingLevel = "number.heat" }
|
||||
Entities = new() { AmbientLight = "light.bedroom" }
|
||||
};
|
||||
private static HomeAssistantState Light(string state, double brightness, DateTimeOffset updated) => new()
|
||||
{
|
||||
EntityId = "light.bedroom", State = state, LastUpdated = updated,
|
||||
Attributes = JsonSerializer.SerializeToElement(new { brightness })
|
||||
};
|
||||
private static DeviceCommand Massage() => new("按摩", "select.right", "select", "select_option",
|
||||
new Dictionary<string, object?> { ["option"] = "全身" }) { Intent = DeviceCommandIntent.StartMassage };
|
||||
|
||||
[Fact]
|
||||
public async Task UnconfiguredInputsAndPlaceholderAudioCannotPretendToWork()
|
||||
@@ -71,7 +67,7 @@ public sealed class SafetyAndReservedWorkflowTests
|
||||
Assert.Equal(ReservedSleepPhase.WaitingForBed, workflow.Phase);
|
||||
Assert.Empty(workflow.Observe(Reading(Now.AddSeconds(30)), Now.AddSeconds(30)));
|
||||
Assert.Empty(workflow.Observe(Reading(Now.AddSeconds(59)), Now.AddSeconds(59)));
|
||||
Assert.Equal(2, workflow.Observe(Reading(Now.AddSeconds(60)), Now.AddSeconds(60)).Count);
|
||||
Assert.Equal(1, workflow.Observe(Reading(Now.AddSeconds(60)), Now.AddSeconds(60)).Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -93,7 +89,7 @@ public sealed class SafetyAndReservedWorkflowTests
|
||||
workflow.Start(); workflow.Observe(Reading(Now), Now);
|
||||
Assert.Empty(workflow.Observe(Reading(Now.AddSeconds(29)), Now.AddSeconds(29)));
|
||||
var actions = workflow.Observe(Reading(Now.AddSeconds(30)), Now.AddSeconds(30));
|
||||
Assert.Contains(actions, action => action.Kind == SleepWorkflowActionKind.StartGentleRightMassage);
|
||||
Assert.Single(actions);
|
||||
Assert.Equal(50, actions.Single(action => action.Kind == SleepWorkflowActionKind.RequestGuidance).VolumePercent);
|
||||
Assert.Empty(workflow.GuidanceCompleted("wrong", true, Now.AddSeconds(50)));
|
||||
var music = Assert.Single(workflow.GuidanceCompleted("guide", true, Now.AddSeconds(50)));
|
||||
@@ -122,55 +118,15 @@ public sealed class SafetyAndReservedWorkflowTests
|
||||
Assert.True(gate.CanRemind("another", Now));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("off", 255)]
|
||||
[InlineData("on", 0)]
|
||||
[InlineData("unavailable", 255)]
|
||||
public async Task OffOrUnconfirmedLampBlocksMassage(string state, double brightness)
|
||||
{
|
||||
var gateway = new FakeHaGateway();
|
||||
gateway.States["light.bedroom"] = Light(state, brightness, Now);
|
||||
var guard = new LightMassageSafetyRule(gateway, Options.Create(Configuration()), new());
|
||||
var runner = new DeviceActionRunner(gateway, TimeProvider.System, new(), [guard]);
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() => runner.SendAsync(Massage(), default));
|
||||
Assert.Empty(gateway.Calls);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task KnownLampOffRejectsOlderCloudOnCacheButAllowsFreshOnReading()
|
||||
{
|
||||
var gateway = new FakeHaGateway();
|
||||
var state = new SceneLightSafetyState(); state.MarkOff(Now);
|
||||
var guard = new LightMassageSafetyRule(gateway, Options.Create(Configuration()), state);
|
||||
gateway.States["light.bedroom"] = Light("on", 100, Now.AddSeconds(-1));
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() => guard.ValidateAsync(Massage(), default));
|
||||
gateway.States["light.bedroom"] = Light("on", 100, Now.AddSeconds(1));
|
||||
await guard.ValidateAsync(Massage(), default);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LateMassageAfterAnOffCommandCannotUndoShutdown()
|
||||
{
|
||||
var gateway = new FakeHaGateway();
|
||||
var guard = new LightMassageSafetyRule(gateway, Options.Create(Configuration()), new());
|
||||
var runner = new DeviceActionRunner(gateway, TimeProvider.System, new(), [guard]);
|
||||
gateway.States["light.bedroom"] = Light("on", 100, DateTimeOffset.UtcNow);
|
||||
await runner.SendAsync(new("关灯", "light.bedroom", "light", "turn_off")
|
||||
{ Intent = DeviceCommandIntent.TurnRelaxationLightOff }, default);
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() => runner.SendAsync(Massage(), default));
|
||||
Assert.DoesNotContain(gateway.Calls, command => command.EntityId == "select.right");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task NaturalFadeToZeroStopsBothMassageSides()
|
||||
public async Task NaturalFadeToZeroOnlyControlsTheLight()
|
||||
{
|
||||
var time = new ManualTestTimeProvider();
|
||||
var gateway = new FakeHaGateway { Time = time };
|
||||
gateway.States["light.bedroom"] = Light("on", 100, time.GetUtcNow());
|
||||
var runner = new DeviceActionRunner(gateway, time, new() { VerificationDelay = TimeSpan.Zero });
|
||||
var mattress = new MattressModule(runner, Options.Create(Configuration()));
|
||||
var safety = new SceneLightSafetyState();
|
||||
var light = new HomeAssistantLightTransitionService(gateway, new([mattress]), Options.Create(Configuration()),
|
||||
var light = new HomeAssistantLightTransitionService(gateway, new([]), Options.Create(Configuration()),
|
||||
NullLogger<HomeAssistantLightTransitionService>.Instance, safety, time);
|
||||
await light.StartSleepAsync(2700, default);
|
||||
for (var step = 1; step <= 50; step++)
|
||||
@@ -179,10 +135,9 @@ public sealed class SafetyAndReservedWorkflowTests
|
||||
var expected = 50 - step;
|
||||
await WaitUntilAsync(() => light.GetStatus().BrightnessPercent == expected && (step != 50 || !light.GetStatus().Running));
|
||||
}
|
||||
await WaitUntilAsync(() => gateway.States.GetValueOrDefault("select.left")?.State == "无");
|
||||
Assert.Equal("off", gateway.States["light.bedroom"].State);
|
||||
Assert.Equal("无", gateway.States["select.right"].State);
|
||||
Assert.NotNull(safety.OffAt);
|
||||
Assert.All(gateway.Calls, command => Assert.Equal("light.bedroom", command.EntityId));
|
||||
await light.StopAsync(default);
|
||||
}
|
||||
|
||||
@@ -195,14 +150,6 @@ public sealed class SafetyAndReservedWorkflowTests
|
||||
Assert.Equal("Failed", (await coordinator.ExecuteAsync("sleep", new(), "balanced", default)).Status);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ManuallyEnabledHeatIsIncludedEvenIfAutomaticMattressStartIsDisabled()
|
||||
{
|
||||
var gateway = new FakeHaGateway();
|
||||
var module = new MattressModule(new(gateway, TimeProvider.System, new()), Options.Create(Configuration()));
|
||||
Assert.Contains(module.GetShutdownCommands(), command => command.EntityId == "number.heat" && command.ExpectedState == "0");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SessionClimateTargetIsIdempotentAndPreviewIsNotRandomized()
|
||||
{
|
||||
|
||||
@@ -4,7 +4,6 @@ using Evergreen.Health.Application.Health.Devices.Contracts;
|
||||
using Evergreen.Health.Application.Health.Devices.Discovery;
|
||||
using Evergreen.Health.Application.Health.Devices.Environment;
|
||||
using Evergreen.Health.Application.Health.Devices.Lighting;
|
||||
using Evergreen.Health.Application.Health.Devices.Mattress;
|
||||
using Evergreen.Health.Application.Health.Integrations.HomeAssistant;
|
||||
using Evergreen.Health.Application.Health.Integrations.MiAirX;
|
||||
using Evergreen.Health.Application.Health.Models;
|
||||
@@ -26,9 +25,8 @@ public sealed class SceneLightingIntegrationTests
|
||||
private static SceneLightOptions StripSettings() => new() { Key = "sleep-light-strip", Name = "测试助眠灯带", EntityId = Strip, SleepEffect = "助眠模式" };
|
||||
private static HomeAssistantOptions Settings() => new()
|
||||
{
|
||||
Entities = new() { AmbientLight = Primary, Climate = Climate, Temperature = Temperature,
|
||||
MattressLeftHeatingLevel = "number.left_heat", MattressRightHeatingLevel = "number.right_heat" },
|
||||
AdditionalSleepLights = [StripSettings()], SleepScene = new() { EnableMattress = true }
|
||||
Entities = new() { AmbientLight = Primary, Climate = Climate, Temperature = Temperature },
|
||||
AdditionalSleepLights = [StripSettings()]
|
||||
};
|
||||
private static HomeAssistantState Light(string id, string state = "off", string[]? effects = null) => new()
|
||||
{
|
||||
@@ -62,7 +60,7 @@ public sealed class SceneLightingIntegrationTests
|
||||
public DeviceActionRunner Runner { get; }
|
||||
public DeviceModuleRegistry Modules { get; }
|
||||
public HealthSceneCoordinator Coordinator { get; }
|
||||
public Fixture(bool mattress = false)
|
||||
public Fixture()
|
||||
{
|
||||
Gateway = new() { Time = Time };
|
||||
Gateway.States[Primary] = Light(Primary); Gateway.States[Strip] = Light(Strip);
|
||||
@@ -77,7 +75,6 @@ public sealed class SceneLightingIntegrationTests
|
||||
new ConfiguredSleepLightModule(Runner, StripSettings(), Lights.ForEntity(Strip)),
|
||||
new ClimateModule(Runner, Options)
|
||||
};
|
||||
if (mattress) modules.Add(new MattressModule(Runner, Options));
|
||||
Modules = new(modules);
|
||||
Coordinator = new(Modules, Runner, Gateway, Lights, new FakeMusic());
|
||||
}
|
||||
@@ -89,10 +86,10 @@ public sealed class SceneLightingIntegrationTests
|
||||
LastReported = Time.GetUtcNow(), Attributes = JsonSerializer.SerializeToElement(new { unit_of_measurement = "°C" })
|
||||
};
|
||||
else Gateway.States.TryRemove(Temperature, out _);
|
||||
var comfort = new MattressComfortService(Gateway, new IndoorEnvironmentReader(Options, Time), Options)
|
||||
var comfort = new EnvironmentAdviceService(Gateway, new IndoorEnvironmentReader(Options, Time), Options)
|
||||
.Get(null, Gateway.States);
|
||||
var config = new PersonalizedSceneConfig { LightColorTemperatureKelvin = 3000 };
|
||||
MattressComfortService.ApplyTo(config, comfort);
|
||||
EnvironmentAdviceService.ApplyTo(config, comfort);
|
||||
RoomTemperaturePolicy.PickTargetForSession(config.ClimateAdvice);
|
||||
return new(config, "balanced");
|
||||
}
|
||||
@@ -134,7 +131,7 @@ public sealed class SceneLightingIntegrationTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BothLightsReachZeroAndOnlyOriginalLightKeepsMassageShutdownHook()
|
||||
public async Task BothLightsReachZeroAndOnlyOriginalLightKeepsLightOffEvent()
|
||||
{
|
||||
var f = new Fixture();
|
||||
try
|
||||
@@ -171,21 +168,21 @@ public sealed class SceneLightingIntegrationTests
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(15, "heat", 1)]
|
||||
[InlineData(30, "cool", 0)]
|
||||
[InlineData(22, "off", 0)]
|
||||
[InlineData(24, "off", 0)]
|
||||
[InlineData(25, "off", 0)]
|
||||
public async Task EnvironmentSensorDrivesActualSceneClimateAndBothHeatingLevels(double room, string mode, int heating)
|
||||
[InlineData(15, "heat")]
|
||||
[InlineData(30, "cool")]
|
||||
[InlineData(22, "off")]
|
||||
[InlineData(24, "off")]
|
||||
[InlineData(25, "off")]
|
||||
public async Task EnvironmentSensorDrivesActualSceneClimateWithoutRetiredHeating(double room, string mode)
|
||||
{
|
||||
var f = new Fixture(mattress: true);
|
||||
var f = new Fixture();
|
||||
try
|
||||
{
|
||||
var prepared = f.Prepare(room);
|
||||
var result = await CompleteAsync(f.Coordinator.ExecutePreparedSleepAsync(_ => Task.FromResult(prepared), default), f.Time);
|
||||
Assert.True(result.Success); Assert.Equal(mode, result.ClimateAdvice!.Mode);
|
||||
Assert.False(result.ClimateAdvice.PendingIntegration);
|
||||
foreach (var id in new[] { "number.left_heat", "number.right_heat" }) Assert.Equal(heating.ToString(), f.Gateway.States[id].State);
|
||||
Assert.DoesNotContain(f.Gateway.Calls, call => call.EntityId is "number.left_heat" or "number.right_heat");
|
||||
if (mode == "off")
|
||||
{
|
||||
Assert.Null(result.ClimateAdvice.TargetTemperatureCelsius);
|
||||
@@ -211,11 +208,10 @@ public sealed class SceneLightingIntegrationTests
|
||||
var prepared = f.Prepare(null);
|
||||
var result = await f.Coordinator.ExecuteAsync("sleep", prepared.Config, "balanced", default);
|
||||
Assert.Equal("unavailable", result.ClimateAdvice!.Mode);
|
||||
Assert.Equal(0, prepared.Config.MattressHeatingLevel);
|
||||
Assert.DoesNotContain(f.Gateway.Calls, call => call.EntityId == Climate);
|
||||
f.Prepare(15); f.Time.Advance(TimeSpan.FromMinutes(31));
|
||||
var comfort = new MattressComfortService(f.Gateway, new IndoorEnvironmentReader(f.Options, f.Time), f.Options).Get(null, f.Gateway.States);
|
||||
Assert.Equal("unavailable", comfort.ClimateAdvice.Mode); Assert.Equal(0, comfort.HeatingLevel);
|
||||
var comfort = new EnvironmentAdviceService(f.Gateway, new IndoorEnvironmentReader(f.Options, f.Time), f.Options).Get(null, f.Gateway.States);
|
||||
Assert.Equal("unavailable", comfort.ClimateAdvice.Mode);
|
||||
}
|
||||
finally { await f.Lights.StopAsync(default); }
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Evergreen.Health.Application.Health.Devices;
|
||||
using Evergreen.Health.Application.Health.Devices.Discovery;
|
||||
using Evergreen.Health.Application.Health.Devices.Mattress;
|
||||
using Evergreen.Health.Application.Health.Devices.Lighting;
|
||||
using Evergreen.Health.Application.Health.Integrations.HomeAssistant;
|
||||
using Evergreen.Health.Application.Health.Scenes;
|
||||
using Microsoft.Extensions.Options;
|
||||
@@ -96,10 +96,10 @@ public sealed class SystemServiceFilteringTests
|
||||
{
|
||||
var options = Options.Create(new HomeAssistantOptions
|
||||
{
|
||||
Entities = new() { MattressLeftHeatingLevel = "number.heating" }
|
||||
Entities = new() { AmbientLight = "light.bedroom" }
|
||||
});
|
||||
var runner = new DeviceActionRunner(new FakeHaGateway(), TimeProvider.System, new());
|
||||
var catalog = new HomeAssistantDeviceCatalog(options, new DeviceModuleRegistry([new MattressModule(runner, options)]));
|
||||
var catalog = new HomeAssistantDeviceCatalog(options, new DeviceModuleRegistry([new LightingModule(runner, options, new FakeLight(), new LightOffDispatcher([]))]));
|
||||
var registry = new HomeAssistantRegistries
|
||||
{
|
||||
Devices = [new() { Id = "backup", Name = "Backup", EntryType = "service" }],
|
||||
@@ -108,9 +108,9 @@ public sealed class SystemServiceFilteringTests
|
||||
var states = new Dictionary<string, HomeAssistantState>
|
||||
{
|
||||
["sensor.backup"] = new() { EntityId = "sensor.backup", State = "idle" },
|
||||
["number.heating"] = new() { EntityId = "number.heating", State = "0" }
|
||||
["light.bedroom"] = new() { EntityId = "light.bedroom", State = "0" }
|
||||
};
|
||||
Assert.Empty(catalog.BuildDiscoveredDevices(registry, states));
|
||||
Assert.Equal("mattress", Assert.Single(catalog.BuildDiscoveredDevices(null, states)).ModuleKey);
|
||||
Assert.Equal("lighting", Assert.Single(catalog.BuildDiscoveredDevices(null, states)).ModuleKey);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user