Skip to content

Commit

Permalink
Merge pull request #154 from pkuehnel/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
pkuehnel authored Jul 20, 2022
2 parents 87f2d43 + edfc84b commit a3df21d
Show file tree
Hide file tree
Showing 28 changed files with 697 additions and 225 deletions.
4 changes: 2 additions & 2 deletions TeslaSolarCharger.Tests/Services/Server/ConfigJsonService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ public void Sets_correct_default_values_on_new_cars()
Assert.Equal(16, car.CarConfiguration.MaximumAmpere);
Assert.Equal(2, car.CarConfiguration.MinimumAmpere);
Assert.Equal(75, car.CarConfiguration.UsableEnergy);
Assert.Equal(DateTime.MaxValue, car.CarState.ShouldStartChargingSince);
Assert.Equal(DateTime.MaxValue, car.CarState.ShouldStopChargingSince);
Assert.Null(car.CarState.ShouldStartChargingSince);
Assert.Null(car.CarState.ShouldStopChargingSince);
}
}

Expand Down
37 changes: 37 additions & 0 deletions TeslaSolarCharger.Tests/Services/Server/GridService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,41 @@ public void Can_Get_Integer_From_Xml_Node_Result(string text)
Assert.Equal(384, intValue);
}

[Theory]
[InlineData(null, null)]
[InlineData("", null)]
[InlineData(" ", null)]
[InlineData(null, "")]
[InlineData(null, " ")]
public void Decides_Correct_Note_Pattern_Type_None(string jsonPattern, string xmlPattern)
{
var gridService = Mock.Create<TeslaSolarCharger.Server.Services.GridService>();
var nodePatternType = gridService.DecideNotePatternType(jsonPattern, xmlPattern);

Assert.Equal(NodePatternType.None, nodePatternType);
}

[Theory]
[InlineData("$.data.overage", null)]
[InlineData("$.data.overage", "")]
[InlineData("$.data.overage", " ")]
public void Decides_Correct_Note_Pattern_Type_Json(string jsonPattern, string xmlPattern)
{
var gridService = Mock.Create<TeslaSolarCharger.Server.Services.GridService>();
var nodePatternType = gridService.DecideNotePatternType(jsonPattern, xmlPattern);

Assert.Equal(NodePatternType.Json, nodePatternType);
}

[Theory]
[InlineData(null, "Device/Measurements/Measurement")]
[InlineData("", "Device/Measurements/Measurement")]
[InlineData(" ", "Device/Measurements/Measurement")]
public void Decides_Correct_Note_Pattern_Type_Xml(string jsonPattern, string xmlPattern)
{
var gridService = Mock.Create<TeslaSolarCharger.Server.Services.GridService>();
var nodePatternType = gridService.DecideNotePatternType(jsonPattern, xmlPattern);

Assert.Equal(NodePatternType.Xml, nodePatternType);
}
}
25 changes: 11 additions & 14 deletions TeslaSolarCharger.Tests/Wrappers/ConfigurationWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public ConfigurationWrapper(ITestOutputHelper outputHelper)
[Fact]
public void Get_Not_Nullable_String()
{
var configurationWrapper = Mock.Create<TeslaSolarCharger.Shared.Wrappers.ConfigurationWrapper>();
var configurationWrapper = Mock.Create<Shared.Wrappers.ConfigurationWrapper>();

var existingConfigValue = "TeslaMateApiBaseUrl";
var teslaMateApiBaseUrl =
Expand All @@ -29,7 +29,7 @@ public void Get_Not_Nullable_String()
[InlineData("notExisiting")]
public void Throw_Exception_On_Null_String(string notExisitingConfigValue)
{
var configurationWrapper = Mock.Create<TeslaSolarCharger.Shared.Wrappers.ConfigurationWrapper>();
var configurationWrapper = Mock.Create<Shared.Wrappers.ConfigurationWrapper>();
Assert.Throws<NullReferenceException>(
() => configurationWrapper.GetNotNullableConfigurationValue<string>(notExisitingConfigValue));
}
Expand All @@ -39,7 +39,7 @@ public void Throw_Exception_On_Null_String(string notExisitingConfigValue)
[InlineData("notExisiting")]
public void Returns_Null_On_Non_Exisiting_Values(string notExisitingConfigValue)
{
var configurationWrapper = Mock.Create<TeslaSolarCharger.Shared.Wrappers.ConfigurationWrapper>();
var configurationWrapper = Mock.Create<Shared.Wrappers.ConfigurationWrapper>();
var value = configurationWrapper.GetNullableConfigurationValue<string>(notExisitingConfigValue);

Assert.Null(value);
Expand All @@ -52,7 +52,7 @@ public void Returns_Null_On_Non_Exisiting_Values(string notExisitingConfigValue)
[InlineData("notExisiting")]
public void Get_TimeSpan_From_Minutes(string configName)
{
var configurationWrapper = Mock.Create<TeslaSolarCharger.Shared.Wrappers.ConfigurationWrapper>();
var configurationWrapper = Mock.Create<Shared.Wrappers.ConfigurationWrapper>();
var timespan =
configurationWrapper.GetMinutesConfigurationValueIfGreaterThanMinumum(configName, TimeSpan.FromMinutes(1));

Expand Down Expand Up @@ -82,7 +82,7 @@ public void Get_TimeSpan_From_Minutes(string configName)
[InlineData("notExisiting")]
public void Get_TimeSpan_From_Seconds(string configName)
{
var configurationWrapper = Mock.Create<TeslaSolarCharger.Shared.Wrappers.ConfigurationWrapper>();
var configurationWrapper = Mock.Create<Shared.Wrappers.ConfigurationWrapper>();
var minimum = TimeSpan.FromSeconds(1);
var timespan =
configurationWrapper.GetSecondsConfigurationValueIfGreaterThanMinumum(configName, minimum);
Expand All @@ -109,21 +109,18 @@ public void Get_TimeSpan_From_Seconds(string configName)
[Fact]
public void GetConfigurationFileDirectory()
{
var configurationWrapper = Mock.Create<TeslaSolarCharger.Shared.Wrappers.ConfigurationWrapper>();
var configurationWrapper = Mock.Create<Shared.Wrappers.ConfigurationWrapper>();
var value = configurationWrapper.ConfigFileDirectory();

Assert.Equal("configs", value);
var dirInfo = new DirectoryInfo(value);
Assert.Equal("configs", dirInfo.Name);
}

[Fact]
public void GetCarConfigurationFileFullName()
{
var configurationWrapper = Mock.Create<TeslaSolarCharger.Shared.Wrappers.ConfigurationWrapper>();
var configurationWrapper = Mock.Create<Shared.Wrappers.ConfigurationWrapper>();
var value = configurationWrapper.CarConfigFileFullName();
var pathSeparator = Path.DirectorySeparatorChar;
var linuxPathSeparator = '/';
var windowsPathSeparator = '\\';
Assert.True(pathSeparator.Equals(linuxPathSeparator) || pathSeparator.Equals(windowsPathSeparator));
Assert.Equal($"configs{pathSeparator}carConfig.json", value);
var fileInfo = new FileInfo(value);
Assert.Equal("carConfig.json", fileInfo.Name);
}
}
168 changes: 168 additions & 0 deletions TeslaSolarCharger/Client/Pages/BaseConfiguration.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
@page "/BaseConfiguration"
@using TeslaSolarCharger.Shared.Dtos.BaseConfiguration
@using System.Runtime.InteropServices
@inject HttpClient HttpClient
@inject IToastService ToastService

<PageTitle>Base Configuration</PageTitle>

<h3>Base Configuration</h3>

@if (_dtoBaseConfiguration == null)
{
<p><em>Loading...</em></p>
}
else
{
<EditForm Model="@_dtoBaseConfiguration" OnValidSubmit="@HandleValidSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<hr />
<div class="form-group">
<label for="carPriorities">Car Ids</label>
<InputText id="carPriorities" @bind-Value="_dtoBaseConfiguration.CarPriorities" placeholder="1|3|2" class="form-control" />
<small id="powerBufferHelp" class="form-text text-muted">Car Ids separated by '|'. Note: The order of the IDs is the order of power distribution.</small>
</div>
<hr />
<div class="form-group">
<label for="currentPowerToGridUrl">Grid Power Url</label>
<InputText id="currentPowerToGridUrl" @bind-Value="_dtoBaseConfiguration.CurrentPowerToGridUrl" class="form-control" />
</div>
<div class="form-group">
<label for="powerBuffer">Power Buffer (Watt)</label>
<InputNumber id="powerBuffer" @bind-Value="_dtoBaseConfiguration.PowerBuffer" class="form-control" />
<small id="powerBufferHelp" class="form-text text-muted">Set values higher than 0 to e.g. charge your home battery first, or lower than minimum adjustable power to charge your car first (e.g. 230V * 1A * 3 phases => -691W).</small>
</div>
<div class="form-group">
<InputCheckbox id="currentPowerToGridInvertValue" @bind-Value="_dtoBaseConfiguration.CurrentPowerToGridInvertValue" class="form-check-input" />
<label for="currentPowerToGridInvertValue">Invert Grid Power Value</label>
<div>
<small id="currentPowerToGridInvertValueHelp" class="form-text text-muted">Use this if consuming power from the grid is a positive value.</small>
</div>
</div>
<div class="form-group">
<label for="currentPowerToGridJsonPattern">Grid Power Json Pattern</label>
<InputText id="currentPowerToGridJsonPattern" @bind-Value="_dtoBaseConfiguration.CurrentPowerToGridJsonPattern" placeholder="$.data.overage" class="form-control" />
</div>
<div class="form-group">
<label for="currentPowerToGridXmlPattern">Grid Power XML Pattern</label>
<InputText id="currentPowerToGridXmlPattern" @bind-Value="_dtoBaseConfiguration.CurrentPowerToGridXmlPattern" placeholder="Device/Measurements/Measurement" class="form-control" />
</div>
<div class="form-group">
<label for="currentPowerToGridXmlAttributeHeaderName">Grid Power XML Attribute Header Name</label>
<InputText id="currentPowerToGridXmlAttributeHeaderName" @bind-Value="_dtoBaseConfiguration.CurrentPowerToGridXmlAttributeHeaderName" placeholder="AttributeHeaderName" class="form-control" />
</div>
<div class="form-group">
<label for="currentPowerToGridXmlAttributeHeaderValue">Grid Power XML Attribute Header Value</label>
<InputText id="currentPowerToGridXmlAttributeHeaderValue" @bind-Value="_dtoBaseConfiguration.CurrentPowerToGridXmlAttributeHeaderValue" placeholder="AttributeHeaderValue" class="form-control" />
</div>
<div class="form-group">
<label for="currentPowerToGridXmlAttributeValueName">Grid Power XML Attribute Header Value</label>
<InputText id="currentPowerToGridXmlAttributeValueName" @bind-Value="_dtoBaseConfiguration.CurrentPowerToGridXmlAttributeValueName" placeholder="AttributeValueName" class="form-control" />
</div>
<hr />
<div class="form-group">
<label for="currentInverterPowerUrl">Inverter Power Url</label>
<InputText id="currentInverterPowerUrl" @bind-Value="_dtoBaseConfiguration.CurrentInverterPowerUrl" class="form-control" />
</div>
<div class="form-group">
<label for="currentInverterPowerJsonPattern">Inverter Power Json Pattern</label>
<InputText id="currentInverterPowerJsonPattern" @bind-Value="_dtoBaseConfiguration.CurrentInverterPowerJsonPattern" placeholder="$.data.overage" class="form-control" />
</div>
<div class="form-group">
<label for="currentPowerToGridXmlPattern">Grid Power XML Pattern</label>
<InputText id="currentPowerToGridXmlPattern" @bind-Value="_dtoBaseConfiguration.CurrentPowerToGridXmlPattern" placeholder="Device/Measurements/Measurement" class="form-control" />
</div>
<div class="form-group">
<label for="currentInverterPowerXmlAttributeHeaderName">Inverter Power XML Attribute Header Name</label>
<InputText id="currentInverterPowerXmlAttributeHeaderName" @bind-Value="_dtoBaseConfiguration.CurrentInverterPowerXmlAttributeHeaderName" placeholder="AttributeHeaderName" class="form-control" />
</div>
<div class="form-group">
<label for="currentInverterPowerXmlAttributeHeaderValue">Inverter Power XML Attribute Header Value</label>
<InputText id="currentInverterPowerXmlAttributeHeaderValue" @bind-Value="_dtoBaseConfiguration.CurrentInverterPowerXmlAttributeHeaderValue" placeholder="AttributeHeaderValue" class="form-control" />
</div>
<div class="form-group">
<label for="currentInverterPowerXmlAttributeValueName">Inverter Power XML Attribute Header Value</label>
<InputText id="currentInverterPowerXmlAttributeValueName" @bind-Value="_dtoBaseConfiguration.CurrentInverterPowerXmlAttributeValueName" placeholder="AttributeValueName" class="form-control" />
</div>
<hr />
<div class="form-group">
<label for="updateIntervalSeconds">Car Power Adjustment Intervall (seconds)</label>
<InputNumber id="updateIntervalSeconds" @bind-Value="_dtoBaseConfiguration.UpdateIntervalSeconds" class="form-control" />
</div>
<div class="form-group">
<label for="pvValueUpdateIntervalSeconds">Solar plant adjustment intervall (seconds)</label>
<InputNumber id="pvValueUpdateIntervalSeconds" @bind-Value="_dtoBaseConfiguration.PvValueUpdateIntervalSeconds" class="form-control" />
</div>
<div class="form-group">
<label for="minutesUntilSwitchOn">Time with enough solar power until charging starts (minutes)</label>
<InputNumber id="minutesUntilSwitchOn" @bind-Value="_dtoBaseConfiguration.MinutesUntilSwitchOn" class="form-control" />
</div>
<div class="form-group">
<label for="minutesUntilSwitchOff">Time without enough solar power until charging stops (minutes)</label>
<InputNumber id="minutesUntilSwitchOff" @bind-Value="_dtoBaseConfiguration.MinutesUntilSwitchOff" class="form-control" />
</div>
<hr />
<div class="form-group">
<label for="teslaMateApiBaseUrl">Teslamate API Base Url</label>
<InputText id="teslaMateApiBaseUrl" @bind-Value="_dtoBaseConfiguration.TeslaMateApiBaseUrl" placeholder="http://teslamateapi:8080" class="form-control" />
<small id="teslaMateApiBaseUrlHelp" class="form-text text-muted">You can use the name of the container and the default port even though you changed the external port.</small>
</div>
<div class="form-group">
<label for="geoFence">Relevant Geofence</label>
<InputText id="geoFence" @bind-Value="_dtoBaseConfiguration.GeoFence" placeholder="http://teslamateapi:8080" class="form-control" />
<small id="geoFenceHelp" class="form-text text-muted">You have to add a geofence with the same name in TeslaMate</small>
</div>
<hr />
<div class="form-group">
<label for="teslaMateDbServer">TeslaMate Database Server Name</label>
<InputText id="teslaMateDbServer" @bind-Value="_dtoBaseConfiguration.TeslaMateDbServer" placeholder="database" class="form-control" />
<small id="geoFenceHelp" class="form-text text-muted">You can use the name of the TeslaMate database container</small>
</div>
<div class="form-group">
<label for="teslaMateDbPort">TeslaMate Database Server Port</label>
<InputNumber id="teslaMateDbPort" @bind-Value="_dtoBaseConfiguration.TeslaMateDbPort" placeholder="5432" class="form-control" />
<small id="geoFenceHelp" class="form-text text-muted">You can use the internal port of the TeslaMate database container</small>
</div>
<div class="form-group">
<label for="teslaMateDbUser">TeslaMate Database Username</label>
<InputText id="teslaMateDbUser" @bind-Value="_dtoBaseConfiguration.TeslaMateDbUser" placeholder="username" class="form-control" />
</div>
<div class="form-group">
<label for="teslaMateDbPassword">TeslaMate Database Server Password</label>
<InputText type="password" id="teslaMateDbPassword" @bind-Value="_dtoBaseConfiguration.TeslaMateDbPassword" placeholder="secret" class="form-control" />
</div>
<hr />
<div class="form-group">
<label for="mosquitoServer">Mosquito servername</label>
<InputText id="mosquitoServer" @bind-Value="_dtoBaseConfiguration.MosquitoServer" placeholder="mosquitto" class="form-control" />
</div>
<div class="form-group">
<label for="mqqtClientId">Mqqt ClientId</label>
<InputText id="mqqtClientId" @bind-Value="_dtoBaseConfiguration.MqqtClientId" placeholder="TeslaSolarCharger" class="form-control" />
</div>
<hr />
<button type="submit" class="btn btn-primary">Submit</button>
</EditForm>
}

@code {
private DtoBaseConfiguration? _dtoBaseConfiguration;

protected override async Task OnInitializedAsync()
{
_dtoBaseConfiguration = await HttpClient.GetFromJsonAsync<DtoBaseConfiguration>("/api/BaseConfiguration/GetBaseConfiguration");
}
private async Task HandleValidSubmit()
{
var result = await HttpClient.PutAsJsonAsync($"api/BaseConfiguration/UpdateBaseConfiguration", _dtoBaseConfiguration);
if (result.IsSuccessStatusCode)
{
ToastService.ShowSuccess("Base Configuration updated");
}
else
{
ToastService.ShowError("Error updating base configuration");
}
}
}
2 changes: 1 addition & 1 deletion TeslaSolarCharger/Client/Pages/CarSettings.razor
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
@inject HttpClient HttpClient
@inject IToastService ToastService


<PageTitle>Car Settings</PageTitle>
<h3>CarSettings</h3>

@if (_carBasicConfigurations == null)
Expand Down
6 changes: 3 additions & 3 deletions TeslaSolarCharger/Client/Pages/Index.razor
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
@inject HttpClient HttpClient
@inject IToastService ToastService

<PageTitle>Index</PageTitle>
<PageTitle>Tesla Solar Charger</PageTitle>

@if (_settings == null)
{
Expand Down Expand Up @@ -194,15 +194,15 @@ else
</tr>
<tr>
<td>
Charge start at
Should start charging since
</td>
<td>
@car.CarState.ShouldStartChargingSince
</td>
</tr>
<tr>
<td>
Charge end at
Should stop charging since
</td>
<td>
@car.CarState.ShouldStopChargingSince
Expand Down
2 changes: 1 addition & 1 deletion TeslaSolarCharger/Client/Shared/MainLayout.razor
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<main>
<div class="top-row px-4">
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
<a href="https://github.com/pkuehnel/TeslaSolarCharger/" target="_blank">About</a>
</div>

<article class="content px-4">
Expand Down
7 changes: 6 additions & 1 deletion TeslaSolarCharger/Client/Shared/NavMenu.razor
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<div class="top-row ps-3 navbar navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="">TeslaSolarCharger</a>
<a class="navbar-brand" href=""><i class="fa-solid fa-solar-panel" style="width: 25px;"></i> Tesla Solar Charger</a>
<button title="Navigation menu" class="navbar-toggler" @onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>
</button>
Expand All @@ -19,6 +19,11 @@
<span class="oi oi-wrench" aria-hidden="true"></span> Car Settings
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="BaseConfiguration">
<span class="oi oi-cog" aria-hidden="true"></span> Base Configuration
</NavLink>
</div>
</nav>
</div>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace TeslaSolarCharger.Server.Contracts;

public interface IEnvironmentVariableConverter
{
Task ConvertAllValues();
}
2 changes: 1 addition & 1 deletion TeslaSolarCharger/Server/Contracts/ITeslaService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace TeslaSolarCharger.Server.Contracts;

public interface ITeslaService
{
Task StartCharging(int carId, int startAmp, CarState? carState);
Task StartCharging(int carId, int startAmp, CarStateEnum? carState);
Task WakeUpCar(int carId);
Task StopCharging(int carId);
Task SetAmp(int carId, int amps);
Expand Down
Loading

0 comments on commit a3df21d

Please sign in to comment.