diff --git a/SmartTeslaAmpSetter.Tests/Services/ChargingService.cs b/SmartTeslaAmpSetter.Tests/Services/ChargingService.cs index 7aa226518..a0fc7d6fd 100644 --- a/SmartTeslaAmpSetter.Tests/Services/ChargingService.cs +++ b/SmartTeslaAmpSetter.Tests/Services/ChargingService.cs @@ -140,6 +140,10 @@ public void Gets_relevant_car_IDs() SoC = 30, SocLimit = 60, }, + CarConfiguration = new CarConfiguration() + { + ShouldBeManaged = true, + }, }, new Car() { @@ -153,6 +157,27 @@ public void Gets_relevant_car_IDs() SoC = 30, SocLimit = 60, }, + CarConfiguration = new CarConfiguration() + { + ShouldBeManaged = true, + }, + }, + new Car() + { + Id = 3, + CarState = new CarState() + { + Geofence = geofence, + PluggedIn = true, + ClimateOn = false, + ChargerActualCurrent = 3, + SoC = 30, + SocLimit = 60, + }, + CarConfiguration = new CarConfiguration() + { + ShouldBeManaged = false, + }, }, }; Mock.Mock().Setup(s => s.Cars).Returns(cars); @@ -182,6 +207,10 @@ public void Gets_irrelevant_cars() SoC = 30, SocLimit = 60, }, + CarConfiguration = new CarConfiguration() + { + ShouldBeManaged = true, + }, }, new Car() { @@ -195,15 +224,37 @@ public void Gets_irrelevant_cars() SoC = 30, SocLimit = 60, }, + CarConfiguration = new CarConfiguration() + { + ShouldBeManaged = true, + }, + }, + new Car() + { + Id = 3, + CarState = new CarState() + { + Geofence = geofence, + PluggedIn = true, + ClimateOn = false, + ChargerActualCurrent = 3, + SoC = 30, + SocLimit = 60, + }, + CarConfiguration = new CarConfiguration() + { + ShouldBeManaged = false, + }, }, }; Mock.Mock().Setup(s => s.Cars).Returns(cars); var chargingService = Mock.Create(); - var irrelevantCars = chargingService.GetIrrelevantCars(new List(){1}); - - Assert.Single(irrelevantCars); + var irrelevantCars = chargingService.GetIrrelevantCars(chargingService.GetRelevantCarIds(geofence)); + + Assert.Equal(2, irrelevantCars.Count); Assert.Contains(2, irrelevantCars.Select(c => c.Id)); + Assert.Contains(3, irrelevantCars.Select(c => c.Id)); } private Car CreateDemoCar(ChargeMode chargeMode, DateTime latestTimeToReachSoC, int soC, int minimumSoC, bool autoFullSpeedCharge) diff --git a/SmartTeslaAmpSetter.Tests/Services/MqttService.cs b/SmartTeslaAmpSetter.Tests/Services/MqttService.cs new file mode 100644 index 000000000..c588f52ce --- /dev/null +++ b/SmartTeslaAmpSetter.Tests/Services/MqttService.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SmartTeslaAmpSetter.Server.Services; +using SmartTeslaAmpSetter.Shared.Dtos.Settings; +using Xunit; +using Xunit.Abstractions; + +namespace SmartTeslaAmpSetter.Tests.Services; + +public class MqttService : TestBase +{ + public MqttService(ITestOutputHelper outputHelper) + : base(outputHelper) + { + } + + [Theory] + [InlineData("1")] + [InlineData("3")] + [InlineData("4")] + [InlineData("5")] + [InlineData("8")] + public void ReducesActualCurrentToLastSetAmpIfDifferenceIsOneAndBelow5A(string value) + { + var cars = new List() + { + new Car() + { + Id = 1, + CarState = new CarState() + { + LastSetAmp = 3, + }, + }, + }; + Mock.Mock().Setup(s => s.Cars).Returns(cars); + + var mqttService = Mock.Create(); + + var teslamateValue = new TeslaMateValue() + { + CarId = 1, + Topic = "charger_actual_current", + Value = value, + }; + mqttService.UpdateCar(teslamateValue); + + switch (value) + { + case "1": + Assert.Equal(1, cars.First().CarState.ChargerActualCurrent); + break; + case "3": + case "4": + Assert.Equal(3, cars.First().CarState.ChargerActualCurrent); + break; + case "5": + Assert.Equal(5, cars.First().CarState.ChargerActualCurrent); + break; + case "8": + Assert.Equal(8, cars.First().CarState.ChargerActualCurrent); + break; + default: + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/SmartTeslaAmpSetter/Client/Pages/CarSettings.razor b/SmartTeslaAmpSetter/Client/Pages/CarSettings.razor index 0f2cb3a93..dadb8e60b 100644 --- a/SmartTeslaAmpSetter/Client/Pages/CarSettings.razor +++ b/SmartTeslaAmpSetter/Client/Pages/CarSettings.razor @@ -31,6 +31,11 @@ else

+

+ + +

} diff --git a/SmartTeslaAmpSetter/Server/Services/ChargingService.cs b/SmartTeslaAmpSetter/Server/Services/ChargingService.cs index 2e6919764..e137aa051 100644 --- a/SmartTeslaAmpSetter/Server/Services/ChargingService.cs +++ b/SmartTeslaAmpSetter/Server/Services/ChargingService.cs @@ -68,24 +68,7 @@ public async Task SetNewChargingValues(bool onlyUpdateValues = false) _logger.LogTrace("Relevant cars: {@relevantCars}", relevantCars); _logger.LogTrace("Irrelevant cars: {@irrlevantCars}", irrelevantCars); - foreach (var relevantCar in relevantCars) - { - relevantCar.CarState.ChargingPowerAtHome = relevantCar.CarState.ChargingPower; - } - - //Do not combine with irrelevant cars because then charging would never start - foreach (var pluggedOutCar in _settings.Cars - .Where(c => c.CarState.PluggedIn != true).ToList()) - { - _logger.LogDebug("Resetting ChargeStart and ChargeStop for car {carId}", pluggedOutCar.Id); - UpdateEarliestTimesAfterSwitch(pluggedOutCar.Id); - pluggedOutCar.CarState.ChargingPowerAtHome = 0; - } - - foreach (var car in irrelevantCars) - { - car.CarState.ChargingPowerAtHome = 0; - } + UpdateChargingPowerAtHome(geofence); if (onlyUpdateValues) { @@ -120,6 +103,30 @@ public async Task SetNewChargingValues(bool onlyUpdateValues = false) } } + private void UpdateChargingPowerAtHome(string geofence) + { + var carsAtHome = _settings.Cars.Where(c => c.CarState.Geofence == geofence).ToList(); + foreach (var car in carsAtHome) + { + car.CarState.ChargingPowerAtHome = car.CarState.ChargingPower; + } + var carsNotAtHome = _settings.Cars.Where(car => !carsAtHome.Select(c => c.Id).Any(i => i == car.Id)).ToList(); + + foreach (var car in carsNotAtHome) + { + car.CarState.ChargingPowerAtHome = 0; + } + + //Do not combine with irrelevant cars because then charging would never start + foreach (var pluggedOutCar in _settings.Cars + .Where(c => c.CarState.PluggedIn != true).ToList()) + { + _logger.LogDebug("Resetting ChargeStart and ChargeStop for car {carId}", pluggedOutCar.Id); + UpdateEarliestTimesAfterSwitch(pluggedOutCar.Id); + pluggedOutCar.CarState.ChargingPowerAtHome = 0; + } + } + internal List GetIrrelevantCars(List relevantCarIds) { return _settings.Cars.Where(car => !relevantCarIds.Any(i => i == car.Id)).ToList(); @@ -150,6 +157,7 @@ internal List GetRelevantCarIds(string geofence) var relevantIds = _settings.Cars .Where(c => c.CarState.Geofence == geofence + && c.CarConfiguration.ShouldBeManaged == true && c.CarState.PluggedIn == true && (c.CarState.ClimateOn == true || c.CarState.ChargerActualCurrent > 0 || diff --git a/SmartTeslaAmpSetter/Server/Services/ConfigJsonService.cs b/SmartTeslaAmpSetter/Server/Services/ConfigJsonService.cs index fd80c346b..e69404f49 100644 --- a/SmartTeslaAmpSetter/Server/Services/ConfigJsonService.cs +++ b/SmartTeslaAmpSetter/Server/Services/ConfigJsonService.cs @@ -174,6 +174,13 @@ public async Task AddCarIdsToSettings() { car.CarConfiguration.MinimumAmpere = 1; } + + if (car.CarConfiguration.ShouldBeManaged == null) + { + var defaultValue = true; + _logger.LogInformation("Car {carId}: {variable} is not set, use default value {defaultValue}", car.Id, nameof(car.CarConfiguration.ShouldBeManaged), defaultValue); + car.CarConfiguration.ShouldBeManaged = defaultValue; + } } _logger.LogDebug("All unset car configurations set."); } diff --git a/SmartTeslaAmpSetter/Server/Services/ConfigService.cs b/SmartTeslaAmpSetter/Server/Services/ConfigService.cs index debfca457..75e85877c 100644 --- a/SmartTeslaAmpSetter/Server/Services/ConfigService.cs +++ b/SmartTeslaAmpSetter/Server/Services/ConfigService.cs @@ -54,6 +54,7 @@ public List GetCarBasicConfigurations() MaximumAmpere = car.CarConfiguration.MaximumAmpere, MinimumAmpere = car.CarConfiguration.MinimumAmpere, UsableEnergy = car.CarConfiguration.UsableEnergy, + ShouldBeManaged = car.CarConfiguration.ShouldBeManaged, }); } @@ -67,5 +68,6 @@ public void UpdateCarBasicConfiguration(int carId, CarBasicConfiguration carBasi car.CarConfiguration.MinimumAmpere = carBasicConfiguration.MinimumAmpere; car.CarConfiguration.MaximumAmpere = carBasicConfiguration.MaximumAmpere; car.CarConfiguration.UsableEnergy = carBasicConfiguration.UsableEnergy; + car.CarConfiguration.ShouldBeManaged = carBasicConfiguration.ShouldBeManaged; } } \ No newline at end of file diff --git a/SmartTeslaAmpSetter/Server/Services/MqttService.cs b/SmartTeslaAmpSetter/Server/Services/MqttService.cs index 2e7b64785..d57915512 100644 --- a/SmartTeslaAmpSetter/Server/Services/MqttService.cs +++ b/SmartTeslaAmpSetter/Server/Services/MqttService.cs @@ -137,7 +137,7 @@ public async Task ConfigureMqttClient() await _mqttClient.SubscribeAsync(mqttSubscribeOptions, CancellationToken.None); } - private void UpdateCar(TeslaMateValue value) + internal void UpdateCar(TeslaMateValue value) { var car = _settings.Cars.First(c => c.Id == value.CarId); @@ -188,6 +188,13 @@ private void UpdateCar(TeslaMateValue value) if (!string.IsNullOrWhiteSpace(value.Value)) { car.CarState.ChargerActualCurrent = Convert.ToInt32(value.Value); + if (car.CarState.ChargerActualCurrent < 5 && + car.CarState.LastSetAmp == car.CarState.ChargerActualCurrent - 1 && + car.CarState.LastSetAmp > 0) + { + _logger.LogWarning("CarId {carId}: Reducing {actualCurrent} from {originalValue} to {newValue} due to error in TeslaApi", car.Id, nameof(car.CarState.ChargerActualCurrent), car.CarState.ChargerActualCurrent, car.CarState.LastSetAmp); + car.CarState.ChargerActualCurrent = car.CarState.LastSetAmp; + } } else { diff --git a/SmartTeslaAmpSetter/Shared/ConfigPropertyResolver.cs b/SmartTeslaAmpSetter/Shared/ConfigPropertyResolver.cs index d0e2624a4..cfbf7c1d4 100644 --- a/SmartTeslaAmpSetter/Shared/ConfigPropertyResolver.cs +++ b/SmartTeslaAmpSetter/Shared/ConfigPropertyResolver.cs @@ -17,6 +17,7 @@ public class ConfigPropertyResolver : DefaultContractResolver nameof(Car.CarConfiguration.MinimumAmpere), nameof(Car.CarConfiguration.MaximumAmpere), nameof(Car.CarConfiguration.UsableEnergy), + nameof(Car.CarConfiguration.ShouldBeManaged), nameof(Car.Id), }; diff --git a/SmartTeslaAmpSetter/Shared/Dtos/CarBasicConfiguration.cs b/SmartTeslaAmpSetter/Shared/Dtos/CarBasicConfiguration.cs index 06c33e38c..2a7163a2f 100644 --- a/SmartTeslaAmpSetter/Shared/Dtos/CarBasicConfiguration.cs +++ b/SmartTeslaAmpSetter/Shared/Dtos/CarBasicConfiguration.cs @@ -12,4 +12,5 @@ public CarBasicConfiguration(int carId, string? carName) public int MaximumAmpere { get; set; } public int MinimumAmpere { get; set; } public int UsableEnergy { get; set; } + public bool? ShouldBeManaged { get; set; } } \ No newline at end of file diff --git a/SmartTeslaAmpSetter/Shared/Dtos/Settings/CarConfiguration.cs b/SmartTeslaAmpSetter/Shared/Dtos/Settings/CarConfiguration.cs index b281a7b7c..3d51c13e2 100644 --- a/SmartTeslaAmpSetter/Shared/Dtos/Settings/CarConfiguration.cs +++ b/SmartTeslaAmpSetter/Shared/Dtos/Settings/CarConfiguration.cs @@ -11,10 +11,12 @@ public class CarConfiguration private int _maximumAmpere; private int _minimumAmpere; private int _usableEnergy; + private bool? _shouldBeManaged; public CarConfiguration() { UpdatedSincLastWrite = true; + _shouldBeManaged = true; } [JsonIgnore] @@ -79,4 +81,14 @@ public int UsableEnergy UpdatedSincLastWrite = true; } } + + public bool? ShouldBeManaged + { + get => _shouldBeManaged; + set + { + _shouldBeManaged = value; + UpdatedSincLastWrite = true; + } + } } \ No newline at end of file