Skip to content

Commit

Permalink
Merge pull request #90 from pkuehnel/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
pkuehnel authored Apr 26, 2022
2 parents 836aa53 + 076f707 commit f766757
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 19 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ The current UI can display the car's names including SOC and SOC Limit + one But

### Charge Modes
Currently there are three different charge modes available:
1. **PV only**: Only PV energy is used to charge unless there is a min SOC Level set. If so the software tries to start charging with maximum power to reach the desired SOC Level in time
1. **PV only**: Only solar energy is used to charge. You can set a SOC level which should be reached at a specific date and time. If solar energy is not enough to reach the set soc level in time, the car starts charging at full speed. Note: To let this work, you have to specify `usable kWh` in the car settings section.
1. **Maximum Power**: Car charges with maximum available power
1. **Min SoC + PV**: If plugged in the car starts charging with maximum power until set Min SoC is reached. After that only PV Power is used to charge the car.

Expand Down
26 changes: 26 additions & 0 deletions SmartTeslaAmpSetter.Tests/Services/GridService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Xunit;
using Xunit.Abstractions;

namespace SmartTeslaAmpSetter.Tests.Services;

public class GridService : TestBase
{
public GridService(ITestOutputHelper outputHelper)
: base(outputHelper)
{
}

[Theory]
[InlineData("384.8746")]
[InlineData("384")]
[InlineData("384.0")]
[InlineData("384.147")]
public void Can_extract_Integers_From_String(string value)
{
var gridService = Mock.Create<Server.Services.GridService>();
var intValue = gridService.GetIntegerFromString(value);

Assert.Equal(384, intValue);
}

}
4 changes: 2 additions & 2 deletions SmartTeslaAmpSetter/Client/Pages/Index.razor
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@ else
@if (car.CarConfiguration.ChargeMode == ChargeMode.PvOnly)
{
<p>
<label class="col-sm-4 col-md-3 col-lg-2" for="date">Datum:</label>
<label class="col-sm-4 col-md-3 col-lg-2" for="date">Date:</label>
<input class="col-sm-6 col-md-3 col-lg-2" value="@car.CarConfiguration.LatestTimeToReachSoC.Date.ToString("yyyy-MM-dd")" type="date" id="date" name="date"
@onchange="@(e => car.CarConfiguration.LatestTimeToReachSoC = DateTime.Parse(e.Value?.ToString() ?? DateTime.MaxValue.ToString(CultureInfo.CurrentCulture)).Date.AddHours(car.CarConfiguration.LatestTimeToReachSoC.Hour).AddMinutes(car.CarConfiguration.LatestTimeToReachSoC.Minute))">
</p>
<p>
<label class="col-sm-4 col-md-3 col-lg-2" for="time">Uhrzeit:</label>
<label class="col-sm-4 col-md-3 col-lg-2" for="time">Time:</label>
<input class="col-sm-6 col-md-3 col-lg-2" value="@car.CarConfiguration.LatestTimeToReachSoC.ToString("HH:mm")" type="time" id="time" name="time"
@onchange="@(e => car.CarConfiguration.LatestTimeToReachSoC = car.CarConfiguration.LatestTimeToReachSoC.Date.AddHours(TimeSpan.Parse(e.Value?.ToString() ?? "00:00").Hours).AddMinutes(TimeSpan.Parse(e.Value?.ToString() ?? "00:00").Minutes))">
</p>
Expand Down
2 changes: 1 addition & 1 deletion SmartTeslaAmpSetter/Server/Contracts/IConfigService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public interface IConfigService
{
Task<ISettings> GetSettings();
ChargeMode ChangeChargeMode(int carId);
void UpdateCarConfiguration(int id, CarConfiguration carConfiguration);
void UpdateCarConfiguration(int carId, CarConfiguration carConfiguration);
List<CarBasicConfiguration> GetCarBasicConfigurations();
void UpdateCarBasicConfiguration(int carId, CarBasicConfiguration carBasicConfiguration);
}
3 changes: 3 additions & 0 deletions SmartTeslaAmpSetter/Server/MqttHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,9 @@ private void UpdateCar(TeslaMateValue value)
case "driving":
car.CarState.State = CarState.Driving;
break;
case "updating":
car.CarState.State = CarState.Updating;
break;
default:
_logger.LogWarning("Unknown car state deteckted: {carState}", value.Value);
car.CarState.State = CarState.Unknown;
Expand Down
8 changes: 6 additions & 2 deletions SmartTeslaAmpSetter/Server/Services/ChargingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ public async Task SetNewChargingValues(bool onlyUpdateValues = false)

var relevantCars = _settings.Cars.Where(c => relevantCarIds.Any(r => c.Id == r)).ToList();

_logger.LogTrace("Relevant cars: {@relevantCars}", relevantCars);
_logger.LogTrace("Irrelevant cars: {@irrlevantCars}", irrelevantCars);

foreach (var relevantCar in relevantCars)
{
relevantCar.CarState.ChargingPowerAtHome = relevantCar.CarState.ChargingPower;
Expand Down Expand Up @@ -174,7 +177,8 @@ private async Task<int> ChangeCarAmp(Car relevantCar, int ampToRegulate)
//Falls MaxPower als Charge Mode: Leistung auf maximal
if (relevantCar.CarConfiguration.ChargeMode == ChargeMode.MaxPower || relevantCar.CarState.AutoFullSpeedCharge)
{
_logger.LogDebug("Max Power Charging");
_logger.LogDebug("Max Power Charging: ChargeMode: {chargeMode}, AutoFullSpeedCharge: {autofullspeedCharge}",
relevantCar.CarConfiguration.ChargeMode, relevantCar.CarState.AutoFullSpeedCharge);
if (relevantCar.CarState.ChargerActualCurrent < maxAmpPerCar)
{
var ampToSet = maxAmpPerCar;
Expand Down Expand Up @@ -234,7 +238,7 @@ private async Task<int> ChangeCarAmp(Car relevantCar, int ampToRegulate)
UpdateEarliestTimesAfterSwitch(relevantCar.Id);
}
//Falls nicht ladend, aber laden soll beginnen
else if (finalAmpsToSet > minAmpPerCar && relevantCar.CarState.ChargerActualCurrent == 0)
else if (finalAmpsToSet >= minAmpPerCar && relevantCar.CarState.ChargerActualCurrent == 0)
{
_logger.LogDebug("Charging should start");
var earliestSwitchOn = EarliestSwitchOn(relevantCar.Id);
Expand Down
8 changes: 6 additions & 2 deletions SmartTeslaAmpSetter/Server/Services/ConfigService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,23 @@ public async Task<ISettings> GetSettings()

public ChargeMode ChangeChargeMode(int carId)
{
_logger.LogTrace("{method},({param1})", nameof(ChangeChargeMode), carId);
var car = _settings.Cars.First(c => c.Id == carId);
car.CarConfiguration.ChargeMode = car.CarConfiguration.ChargeMode.Next();
car.CarState.AutoFullSpeedCharge = false;
return car.CarConfiguration.ChargeMode;
}

public void UpdateCarConfiguration(int id, CarConfiguration carConfiguration)
public void UpdateCarConfiguration(int carId, CarConfiguration carConfiguration)
{
var existingCarIndex = _settings.Cars.FindIndex(c => c.Id == id);
_logger.LogTrace("{method}({param1}, {@param2})", nameof(UpdateCarConfiguration), carId, carConfiguration);
var existingCarIndex = _settings.Cars.FindIndex(c => c.Id == carId);
_settings.Cars[existingCarIndex].CarConfiguration = carConfiguration;
}

public List<CarBasicConfiguration> GetCarBasicConfigurations()
{
_logger.LogTrace("{method}()", nameof(GetCarBasicConfigurations));
var carSettings = new List<CarBasicConfiguration>();

foreach (var car in _settings.Cars)
Expand All @@ -59,6 +62,7 @@ public List<CarBasicConfiguration> GetCarBasicConfigurations()

public void UpdateCarBasicConfiguration(int carId, CarBasicConfiguration carBasicConfiguration)
{
_logger.LogTrace("{method}({param1}, {@param2})", nameof(UpdateCarBasicConfiguration), carId, carBasicConfiguration);
var car = _settings.Cars.First(c => c.Id == carId);
car.CarConfiguration.MinimumAmpere = carBasicConfiguration.MinimumAmpere;
car.CarConfiguration.MaximumAmpere = carBasicConfiguration.MaximumAmpere;
Expand Down
51 changes: 40 additions & 11 deletions SmartTeslaAmpSetter/Server/Services/GridService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Newtonsoft.Json.Linq;
using System.Globalization;
using Newtonsoft.Json.Linq;
using SmartTeslaAmpSetter.Server.Contracts;

namespace SmartTeslaAmpSetter.Server.Services;
Expand All @@ -7,22 +8,31 @@ public class GridService : IGridService
{
private readonly ILogger<GridService> _logger;
private readonly IConfiguration _configuration;
private readonly ITelegramService _telegramService;

public GridService(ILogger<GridService> logger, IConfiguration configuration)
public GridService(ILogger<GridService> logger, IConfiguration configuration, ITelegramService telegramService)
{
_logger = logger;
_configuration = configuration;
_telegramService = telegramService;
}

public async Task<int> GetCurrentOverage()
{
_logger.LogTrace("{method}()", nameof(GetCurrentOverage));
using var httpClient = new HttpClient();
var requestUri = _configuration.GetValue<string>("CurrentPowerToGridUrl");
_logger.LogDebug("Using {uri} to get current overage.", requestUri);
var response = await httpClient.GetAsync(
requestUri)
.ConfigureAwait(false);
response.EnsureSuccessStatusCode();

if (!response.IsSuccessStatusCode)
{
_logger.LogError("Could not get current overage. {statusCode}, {reasonPhrase}", response.StatusCode, response.ReasonPhrase);
response.EnsureSuccessStatusCode();
}

var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

var jsonPattern = _configuration.GetValue<string>("CurrentPowerToGridJsonPattern");
Expand All @@ -34,16 +44,26 @@ public async Task<int> GetCurrentOverage()
throw new InvalidOperationException("Extracted Json Value is null")).Value<string>();
}

if (int.TryParse(result, out var overage))
try
{
var overage = GetIntegerFromString(result);
if (_configuration.GetValue<bool>("CurrentPowerToGridInvertValue"))
{
overage = -overage;
}
return overage;
return overage ;
}
catch (Exception)
{
throw new InvalidCastException($"Could not parse result {result} from uri {requestUri} to integer");
}

}

throw new InvalidCastException($"Could not parse result {result} from uri {requestUri} to integer");
internal int GetIntegerFromString(string? inputString)
{
_logger.LogTrace("{method}({param})", nameof(GetIntegerFromString), inputString);
return (int) double.Parse(inputString ?? throw new ArgumentNullException(nameof(inputString)), CultureInfo.InvariantCulture);
}

public async Task<int?> GetCurrentInverterPower()
Expand All @@ -58,14 +78,23 @@ public async Task<int> GetCurrentOverage()
var response = await httpClient.GetAsync(
requestUri)
.ConfigureAwait(false);
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

if (int.TryParse(result, out var overage))
if (!response.IsSuccessStatusCode)
{
return overage;
_logger.LogWarning("Getting current inverter power did result in statuscode {statusCode} with reason {reasonPhrase}", response.StatusCode, response.ReasonPhrase);
await _telegramService.SendMessage(
$"Getting current inverter power did result in statuscode {response.StatusCode} with reason {response.ReasonPhrase}");
return null;
}
var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

throw new InvalidCastException($"Could not parse result {result} from uri {requestUri} to integer");
try
{
return GetIntegerFromString(result);
}
catch (Exception)
{
throw new InvalidCastException($"Could not parse result {result} from uri {requestUri} to integer");
}
}
}
3 changes: 3 additions & 0 deletions SmartTeslaAmpSetter/Server/Services/TelegramService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ public async Task<HttpStatusCode> SendMessage(string message)
}

var requestUri = CreateRequestUri(message, botKey, channel);

httpClient.Timeout = TimeSpan.FromSeconds(1);

var response = await httpClient.GetAsync(
requestUri);

Expand Down
1 change: 1 addition & 0 deletions SmartTeslaAmpSetter/Shared/Enums/CarState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ public enum CarState
Charging,
Suspended,
Driving,
Updating,
Unknown,
}

0 comments on commit f766757

Please sign in to comment.