Skip to content

Commit

Permalink
Merge pull request #1306 from pkuehnel/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
pkuehnel authored Jun 9, 2024
2 parents fe30f13 + 9d1adf1 commit 85349c7
Show file tree
Hide file tree
Showing 10 changed files with 136 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
[Parameter]
public string ButtonText { get; set; }
[Parameter]
public string StartIcon { get; set; } = Icons.Material.Filled.Add;
public string StartIcon { get; set; }

[Parameter]
public EventCallback OnButtonClicked { get; set; }
Expand Down
60 changes: 51 additions & 9 deletions TeslaSolarCharger/Client/Pages/CarSettings.razor
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
@page "/CarSettings"
@using TeslaSolarCharger.Shared.Dtos
@using TeslaSolarCharger.Client.Wrapper
@using TeslaSolarCharger.Shared.Dtos.Ble
@using Newtonsoft.Json
@inject HttpClient HttpClient
@inject ISnackbar Snackbar

Expand All @@ -27,25 +29,54 @@ else
<GenericInput For="() => carBasicConfiguration.ShouldSetChargeStartTimes" />
<GenericInput For="() => carBasicConfiguration.UseBle" />
</EditFormComponent>
<hr />
<h3>BLE Pairing and test</h3>
<div>
Note: Before TSC can update charge speed via BLE you must pair the car with TSC.
TSC can use BLE instead of the Fleet API. This is useful to come around rate limits.
</div>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="_ => PairCar(carBasicConfiguration.Vin)">Ble Pair</MudButton>
@if (_pairingResults.TryGetValue(carBasicConfiguration.Vin, out var result))
{

<div class="alert alert-info" role="alert">
<p>
@result
</p>

</div>

}
<div>
Note: When clicking the pair button the car won't display any feedback. You have to place the card on the center console. Only after doing so, a message will pop up. If you don't see a message, the pairing failed. As the car does not send any feedback, just try a few times, if it still does not work reboot your BLE device.
</div>
<RightAlignedButtonComponent OnButtonClicked="_ => PairCar(carBasicConfiguration.Vin)" ButtonText="BLE Pair"></RightAlignedButtonComponent>
<h5>Test BLE access</h5>
<div>
@if (_pairingResults.ContainsKey(carBasicConfiguration.Vin))
{
@_pairingResults[carBasicConfiguration.Vin]
}
Before you can test BLE access you must pair the car with TSC. This includes placing the card on your center console and confirming the new "phone key" on the car's screen.
</div>
<div>
After clicking the test button the front lights should flash.
</div>
@if (_bleTestResults.TryGetValue(carBasicConfiguration.Vin, out var bleResult))
{
<div class="@($"alert alert-{(bleResult.Success ? "success" : "danger")}")" role="alert">
<p>
@bleResult.Message
</p>
</div>
}
<RightAlignedButtonComponent OnButtonClicked="_ => TestBle(carBasicConfiguration.Vin)" ButtonText="Flash lights"></RightAlignedButtonComponent>

</div>
</div>
}
}

@code {
private List<CarBasicConfiguration>? _carBasicConfigurations;
private readonly List<int> _savingCarIds = new();

private Dictionary<string, string> _pairingResults = new Dictionary<string, string>();
private Dictionary<string, string> _pairingResults = new();

private Dictionary<string, DtoBleResult> _bleTestResults = new();

protected override async Task OnInitializedAsync()
{
Expand All @@ -70,7 +101,18 @@ else
private async Task PairCar(string vin)
{
var result = await HttpClient.GetStringAsync($"/api/Ble/PairKey?vin={vin}").ConfigureAwait(false);
_pairingResults[vin] = result;
var resultJson = JsonConvert.DeserializeObject<DtoBleResult>(result);
_pairingResults[vin] = resultJson?.Message ?? result;
}

private async Task TestBle(string vin)
{
var result = await HttpClient.GetFromJsonAsync<DtoBleResult>($"/api/Ble/FlashLights?vin={vin}").ConfigureAwait(false) ?? new DtoBleResult { Success = false, Message = "Could not deserialize message from TSC." };
if(result.Success && string.IsNullOrWhiteSpace(result.Message))
{
result.Message = "Ble success seems to work. Please double check if lights were flashing.";
}
_bleTestResults[vin] = result;
}

}
7 changes: 6 additions & 1 deletion TeslaSolarCharger/Server/Controllers/BleController.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
using Microsoft.AspNetCore.Mvc;
using TeslaSolarCharger.Server.Dtos.Ble;
using TeslaSolarCharger.Server.Services.Contracts;
using TeslaSolarCharger.Shared.Dtos.Ble;
using TeslaSolarCharger.SharedBackend.Abstracts;

namespace TeslaSolarCharger.Server.Controllers;

public class BleController (IBleService bleService) : ApiBaseController
{
[HttpGet]
public Task<string> PairKey(string vin) => bleService.PairKey(vin);
public Task<DtoBleResult> PairKey(string vin) => bleService.PairKey(vin);

[HttpGet]
public Task StartCharging(string vin) => bleService.StartCharging(vin);
Expand All @@ -17,4 +19,7 @@ public class BleController (IBleService bleService) : ApiBaseController

[HttpGet]
public Task SetAmp(string vin, int amps) => bleService.SetAmp(vin, amps);

[HttpGet]
public Task<DtoBleResult> FlashLights(string vin) => bleService.FlashLights(vin);
}
7 changes: 5 additions & 2 deletions TeslaSolarCharger/Server/Services/Contracts/IBleService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using TeslaSolarCharger.Shared.Enums;
using TeslaSolarCharger.Server.Dtos.Ble;
using TeslaSolarCharger.Shared.Dtos.Ble;
using TeslaSolarCharger.Shared.Enums;

namespace TeslaSolarCharger.Server.Services.Contracts;

Expand All @@ -7,5 +9,6 @@ public interface IBleService
Task StartCharging(string vin);
Task StopCharging(string vin);
Task SetAmp(string vin, int amps);
Task<string> PairKey(string vin);
Task<DtoBleResult> FlashLights(string vin);
Task<DtoBleResult> PairKey(string vin);
}
74 changes: 56 additions & 18 deletions TeslaSolarCharger/Server/Services/TeslaBleService.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using Newtonsoft.Json;
using System.Net;
using System.Web;
using TeslaSolarCharger.Server.Dtos.Ble;
using TeslaSolarCharger.Server.Services.ApiServices.Contracts;
using TeslaSolarCharger.Server.Services.Contracts;
using TeslaSolarCharger.Shared.Contracts;
using TeslaSolarCharger.Shared.Dtos.Ble;
using TeslaSolarCharger.Shared.Dtos.Contracts;
using TeslaSolarCharger.Shared.Enums;

Expand Down Expand Up @@ -52,28 +54,50 @@ public async Task SetAmp(string vin, int amps)
var result = await SendCommandToBle(request).ConfigureAwait(false);
}

public async Task<string> PairKey(string vin)
public async Task<DtoBleResult> FlashLights(string vin)
{
var request = new DtoBleRequest
{
Vin = vin,
CommandName = "flash-lights",
};
var result = await SendCommandToBle(request).ConfigureAwait(false);
return result;
}

public async Task<DtoBleResult> PairKey(string vin)
{
logger.LogTrace("{method}({vin})", nameof(PairKey), vin);
var bleBaseUrl = configurationWrapper.BleBaseUrl();
if (!bleBaseUrl.EndsWith("/"))
if (string.IsNullOrWhiteSpace(bleBaseUrl))
{
bleBaseUrl += "/";
return new DtoBleResult() { Message = "BLE Base Url is not set.", StatusCode = HttpStatusCode.BadRequest, Success = false, };
}

bleBaseUrl += "Pairing/PairCar";
var queryString = HttpUtility.ParseQueryString(string.Empty);
queryString.Add("vin", vin);
var url = $"{bleBaseUrl}?{queryString}";
logger.LogTrace("Ble Url: {bleUrl}", url);
using var client = new HttpClient();
var response = await client.GetAsync(url).ConfigureAwait(false);
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
try
{
var response = await client.GetAsync(url).ConfigureAwait(false);
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
return new DtoBleResult() { Message = responseContent, StatusCode = response.StatusCode, Success = false, };
}

// Success is unknown as the response is not known
return new DtoBleResult() { Message = responseContent, StatusCode = response.StatusCode, Success = false };
}
catch (Exception ex)
{
logger.LogError("Failed to send command to BLE. StatusCode: {statusCode} {responseContent}", response.StatusCode, responseContent);
throw new InvalidOperationException();
logger.LogError(ex, "Failed to pair key.");
return new DtoBleResult() { Message = ex.Message, StatusCode = HttpStatusCode.InternalServerError, Success = false, };
}
return responseContent;

}

public Task SetScheduledCharging(int carId, DateTimeOffset? chargingStartTime)
Expand All @@ -90,9 +114,14 @@ private async Task<DtoBleResult> SendCommandToBle(DtoBleRequest request)
{
logger.LogTrace("{method}({@request})", nameof(SendCommandToBle), request);
var bleBaseUrl = configurationWrapper.BleBaseUrl();
if (!bleBaseUrl.EndsWith("/"))
if (string.IsNullOrWhiteSpace(bleBaseUrl))
{
bleBaseUrl += "/";
return new DtoBleResult()
{
Success = false,
Message = "BLE Base Url is not set.",
StatusCode = HttpStatusCode.BadRequest,
};
}
bleBaseUrl += "Command/ExecuteCommand";
var queryString = HttpUtility.ParseQueryString(string.Empty);
Expand All @@ -102,15 +131,24 @@ private async Task<DtoBleResult> SendCommandToBle(DtoBleRequest request)
logger.LogTrace("Ble Url: {bleUrl}", url);
logger.LogTrace("Parameters: {@parameters}", request.Parameters);
using var client = new HttpClient();
var response = await client.PostAsJsonAsync(url, request.Parameters).ConfigureAwait(false);
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
try
{
var response = await client.PostAsJsonAsync(url, request.Parameters).ConfigureAwait(false);
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
logger.LogError("Failed to send command to BLE. StatusCode: {statusCode} {responseContent}", response.StatusCode, responseContent);
throw new InvalidOperationException();
}
var result = JsonConvert.DeserializeObject<DtoBleResult>(responseContent);
return result ?? throw new InvalidDataException($"Could not parse {responseContent} to {nameof(DtoBleResult)}");
}
catch (Exception ex)
{
logger.LogError("Failed to send command to BLE. StatusCode: {statusCode} {responseContent}", response.StatusCode, responseContent);
throw new InvalidOperationException();
logger.LogError(ex, "Failed to send ble command.");
return new DtoBleResult() { Message = ex.Message, StatusCode = HttpStatusCode.InternalServerError, Success = false, };
}
var result = JsonConvert.DeserializeObject<DtoBleResult>(responseContent);
return result ?? throw new InvalidDataException($"Could not parse {responseContent} to {nameof(DtoBleResult)}");

}

private async Task WakeUpCarIfNeeded(int carId, CarStateEnum? carState)
Expand Down
1 change: 1 addition & 0 deletions TeslaSolarCharger/Server/appsettings.Development.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"AllowCORS": true,
"DisplayApiRequestCounter": true,
"IgnoreSslErrors": true,
"BleBaseUrl": "http://raspible:7210/",
"GridPriceProvider": {
"EnergyProvider": "Tibber",
"Octopus": {
Expand Down
2 changes: 1 addition & 1 deletion TeslaSolarCharger/Server/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
"GetVehicleDataFromTesla": false,
"GetVehicleDataFromTeslaDebug": false,
"AwattarBaseUrl": "https://api.awattar.de/v1/marketdata",
"BleBaseUrl": "http://raspible:7210/api",
"BleBaseUrl": null,
"GridPriceProvider": {
"EnergyProvider": "FixedPrice",
"Octopus": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,5 @@ public interface IConfigurationWrapper
bool GetVehicleDataFromTesla();
bool GetVehicleDataFromTeslaDebug();
int? MaxInverterAcPower();
string BleBaseUrl();
string? BleBaseUrl();
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Net;

namespace TeslaSolarCharger.Server.Dtos.Ble;
namespace TeslaSolarCharger.Shared.Dtos.Ble;

public class DtoBleResult
{
Expand Down
15 changes: 13 additions & 2 deletions TeslaSolarCharger/Shared/Wrappers/ConfigurationWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,21 @@ public string FleetApiClientId()
return value;
}

public string BleBaseUrl()
public string? BleBaseUrl()
{
var environmentVariableName = "BleBaseUrl";
var value = GetNotNullableConfigurationValue<string>(environmentVariableName);
var value = configuration.GetValue<string?>(environmentVariableName);
if (!string.IsNullOrWhiteSpace(value))
{
if (!value.EndsWith("/"))
{
value += "/";
}
if (!value.EndsWith("/api/"))
{
value += "api/";
}
}
return value;
}

Expand Down

0 comments on commit 85349c7

Please sign in to comment.