Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Develop #1817

Merged
merged 36 commits into from
Feb 11, 2025
Merged

Develop #1817

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
60ee0f0
feat(logging): log into memory and remove seq
pkuehnel Feb 7, 2025
79d2950
feat(chore): remove unused sinks
pkuehnel Feb 7, 2025
c17ffe3
refactor(chore): remove unnecessary code
pkuehnel Feb 7, 2025
e09f7c9
refactor(packages): remove seq
pkuehnel Feb 7, 2025
7b8bef7
fix(chore): fix logging
pkuehnel Feb 7, 2025
67a2dc6
fix(appsettings.json) restore deleted entries
pkuehnel Feb 7, 2025
70b2d9a
fix(appsettings.json): remove restricetedToMinimumLevel
pkuehnel Feb 7, 2025
6b2fb7f
feat(Serilog): add in Memory sink and configure logging in code
pkuehnel Feb 7, 2025
42be754
feat(DebugController): download logs as file
pkuehnel Feb 7, 2025
cc7a2ce
feat(Support): add download logs button
pkuehnel Feb 7, 2025
acd3e63
feat(Debug): change logs file ending
pkuehnel Feb 7, 2025
b4ad7b4
fix(InMemorySink): remove leading and trailing white spaces
pkuehnel Feb 7, 2025
f4d96c6
Merge pull request #1816 from pkuehnel/feat/improveLogging
pkuehnel Feb 7, 2025
09a2741
feat(InMemorySink): increase in memory log capacity
pkuehnel Feb 8, 2025
ea40b5e
Merge pull request #1819 from pkuehnel/feat/increaseInMemorySinkData
pkuehnel Feb 8, 2025
d580010
feat(ConfigurationWrapper): can decide if to use beta endpoints
pkuehnel Feb 8, 2025
7f2148e
feat(chore): decide if to use beta endpoints based on version number
pkuehnel Feb 8, 2025
51f933e
Merge pull request #1818 from pkuehnel/feat/addBetaEndpoints
pkuehnel Feb 8, 2025
ed832f5
feat(TeslaFleetApiService): detect car beeing online
pkuehnel Feb 8, 2025
f41f95b
Merge pull request #1820 from pkuehnel/fix/detectOnlineState
pkuehnel Feb 8, 2025
c84aa7c
feat(SupportRazor): can show Fleet Telemetry config from car
pkuehnel Feb 8, 2025
859da5e
Merge pull request #1821 from pkuehnel/feat/showFleetTelemetryConfigI…
pkuehnel Feb 8, 2025
223a03f
fix(ConfigJsonService): set tesla mate car ID if not set correctly
pkuehnel Feb 8, 2025
88073bf
Merge pull request #1822 from pkuehnel/fix/setCorrectTeslaMateCarId
pkuehnel Feb 8, 2025
2bca3d8
fix(BaseConfigurationRazor): allow edit of teslamate db name
pkuehnel Feb 9, 2025
2acd52e
Merge pull request #1823 from pkuehnel/fix/allowEditTeslaMateDbName
pkuehnel Feb 9, 2025
9cd18b6
feat(SupportRazor): display if car is available in Tesla account
pkuehnel Feb 9, 2025
b47ef08
feat(FleetTelemetryWebSocketService): can handle max configs error me…
pkuehnel Feb 9, 2025
55b3597
feat(SupportRazor): show tooltip on car not part of account
pkuehnel Feb 9, 2025
188c64f
feat(FleetTelemetryConfigurationService): can configure fleet telemet…
pkuehnel Feb 9, 2025
76b502b
feat(FleetTelemetryConfigurationService): handle configuration errors
pkuehnel Feb 9, 2025
603c1b8
feat(SupportRazor): can display error messages in fleet Telemetry con…
pkuehnel Feb 9, 2025
701844c
feat(SupportRazor): improve page styling
pkuehnel Feb 9, 2025
cc01337
Merge pull request #1824 from pkuehnel/feat/allowForceFleetTelemetryR…
pkuehnel Feb 9, 2025
59b262f
feat(FleetTelemetryConnection): do not call fleet telemetry connect i…
pkuehnel Feb 9, 2025
d42f7fe
Merge pull request #1825 from pkuehnel/feat/separateFleetTelemetryWeb…
pkuehnel Feb 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions PkSoftwareService.Custom.Backend/InMemorySink.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using Serilog.Core;
using Serilog.Events;
using Serilog.Formatting.Display;

namespace PkSoftwareService.Custom.Backend;

public class InMemorySink : ILogEventSink
{
private readonly int _capacity;
private readonly Queue<string> _logMessages;
private readonly object _syncRoot = new object();
private readonly MessageTemplateTextFormatter _formatter;

/// <summary>
/// Creates a new InMemorySink.
/// </summary>
/// <param name="outputTemplate">The output template (should match your Console sink).</param>
/// <param name="formatProvider">Optional format provider.</param>
/// <param name="capacity">Max number of messages to store.</param>
public InMemorySink(string outputTemplate, IFormatProvider? formatProvider = null, int capacity = 20000)
{
_capacity = capacity;
_logMessages = new Queue<string>(capacity);
_formatter = new MessageTemplateTextFormatter(outputTemplate, formatProvider);
}

public void Emit(LogEvent logEvent)
{
// Format the log event into a string.
using var writer = new StringWriter();
_formatter.Format(logEvent, writer);
var message = writer.ToString();

// Ensure thread safety while enqueuing/dequeuing.
lock (_syncRoot)
{
if (_logMessages.Count >= _capacity)
{
_logMessages.Dequeue(); // remove oldest
}
_logMessages.Enqueue(message);
}
}

/// <summary>
/// Returns a snapshot of the current log messages.
/// </summary>
public List<string> GetLogs()
{
lock (_syncRoot)
{
return _logMessages.Select(x => x.Trim()).ToList();
}
}

/// <summary>
/// Optionally clear all logs.
/// </summary>
public void Clear()
{
lock (_syncRoot)
{
_logMessages.Clear();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Serilog" Version="4.0.0" />
</ItemGroup>

</Project>
6 changes: 6 additions & 0 deletions TeslaSolarCharger.sln
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TeslaSolarCharger.SharedMod
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TeslaSolarCharger.Services", "TeslaSolarCharger.Services\TeslaSolarCharger.Services.csproj", "{21A8DB64-E449-474E-94DD-360C30D1756A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PkSoftwareService.Custom.Backend", "PkSoftwareService.Custom.Backend\PkSoftwareService.Custom.Backend.csproj", "{B9331EFC-2B31-4447-B6C3-3E898B560946}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -87,6 +89,10 @@ Global
{21A8DB64-E449-474E-94DD-360C30D1756A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{21A8DB64-E449-474E-94DD-360C30D1756A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{21A8DB64-E449-474E-94DD-360C30D1756A}.Release|Any CPU.Build.0 = Release|Any CPU
{B9331EFC-2B31-4447-B6C3-3E898B560946}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B9331EFC-2B31-4447-B6C3-3E898B560946}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B9331EFC-2B31-4447-B6C3-3E898B560946}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B9331EFC-2B31-4447-B6C3-3E898B560946}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
14 changes: 11 additions & 3 deletions TeslaSolarCharger/Client/Pages/BaseConfiguration.razor
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,21 @@ else
</InputComponent>

<InputComponent ValueId="teslaMateDbPort"
LabelText="TeslaMate Database Server Port"
UnitText=""
HelpText="You can use the internal port of the TeslaMate database container">
LabelText="TeslaMate Database Server Port"
UnitText=""
HelpText="You can use the internal port of the TeslaMate database container">
<InputFragment>
<InputNumber id="teslaMateDbPort" @bind-Value="_dtoBaseConfiguration.TeslaMateDbPort" class="form-control" placeholder=" " />
</InputFragment>
</InputComponent>
<InputComponent ValueId="teslaMateDbName"
LabelText="TeslaMate Database Name"
UnitText=""
HelpText="">
<InputFragment>
<InputText id="teslaMateDbName" @bind-Value="_dtoBaseConfiguration.TeslaMateDbDatabaseName" class="form-control" placeholder=" " />
</InputFragment>
</InputComponent>
<InputComponent ValueId="teslaMateDbUser"
LabelText="TeslaMate Database Username"
UnitText=""
Expand Down
41 changes: 36 additions & 5 deletions TeslaSolarCharger/Client/Pages/CarSettings.razor
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
@using TeslaSolarCharger.Client.Wrapper
@using TeslaSolarCharger.Shared.Dtos.Ble
@using Newtonsoft.Json
@using TeslaSolarCharger.Client.Helper.Contracts
@using TeslaSolarCharger.Shared.Enums
@inject HttpClient HttpClient
@inject IHttpClientHelper HttpClientHelper
@inject ISnackbar Snackbar

<PageTitle>Car Settings</PageTitle>
Expand Down Expand Up @@ -68,22 +70,36 @@ else
@if (carBasicConfiguration.Item.UseFleetTelemetry && !carBasicConfiguration.Item.IncludeTrackingRelevantFields)
{
<MudAlert Severity="Severity.Info"
NoIcon="true"
ContentAlignment="HorizontalAlignment.Left">
NoIcon="true"
ContentAlignment="HorizontalAlignment.Left">
<h5>Home Address of Tesla is used to determine if car is at home</h5>
As tracking relevant fields are not included, the home address set in the car is used to determine if the car is at home. This means the Home Geofence set in <MudLink Href="/BaseConfiguration">Base Configuration</MudLink> is not used for this car.
</MudAlert>
}
@if (carBasicConfiguration.Item.UseFleetTelemetry)
{
<GenericInput T="bool"
For="() => carBasicConfiguration.Item.IncludeTrackingRelevantFields"
OnValueChanged="Redraw"/>
For="() => carBasicConfiguration.Item.IncludeTrackingRelevantFields"
OnValueChanged="Redraw" />
}
}

</EditFormComponent>

@if (carBasicConfiguration.Item.ShouldBeManaged && carBasicConfiguration.Item.UseFleetTelemetry)
{
<h3>Fleet Telemetry Config</h3>
@if (_fleetTelemetryConfigs.TryGetValue(carBasicConfiguration.Item.Vin, out var fleetTelemetryConfig))
{
<div>
<h5>Current Fleet Telemetry Config</h5>
<div>@fleetTelemetryConfig</div>
</div>
}
<RightAlignedButtonComponent ButtonText="Get Fleet Telemetry Config"
OnButtonClicked="_ => GetFleetTelemetryConfig(carBasicConfiguration.Item.Vin)"></RightAlignedButtonComponent>
}

@if (_vinsToShowBleTest.Contains(carBasicConfiguration.Item.Vin))
{
<hr />
Expand All @@ -98,7 +114,6 @@ else
<p>
@result
</p>

</div>

}
Expand Down Expand Up @@ -152,6 +167,7 @@ else
private Dictionary<string, string> _pairingResults = new();
private Dictionary<string, DtoBleCommandResult> _bleTestResults = new();
private Dictionary<string, DtoBleCommandResult> _bleWakeUpTestResults = new();
private Dictionary<string, string> _fleetTelemetryConfigs = new();

private HashSet<string> _loadingVins = new();

Expand Down Expand Up @@ -252,4 +268,19 @@ else
}
}

private async Task GetFleetTelemetryConfig(string vin)
{
var result = await HttpClientHelper.SendGetRequestAsync<DtoValue<string>>($"api/Config/GetFleetTelemetryConfiguration?vin={Uri.EscapeDataString(vin)}");
string stringToDisplay;
if (result.HasError)
{
stringToDisplay = result.ErrorMessage ?? "No error message";
}
else
{
stringToDisplay = result.Data?.Value ?? "No data";
}
_fleetTelemetryConfigs[vin] = stringToDisplay;
}

}
142 changes: 142 additions & 0 deletions TeslaSolarCharger/Client/Pages/Support.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
@page "/support"
@using TeslaSolarCharger.Client.Helper.Contracts
@using TeslaSolarCharger.Shared.Dtos
@using TeslaSolarCharger.Shared.Dtos.Support

@inject IHttpClientHelper HttpClientHelper
@inject ISnackbar Snackbar
@inject NavigationManager NavigationManager

<h1>Support</h1>

<MudAlert Severity="Severity.Warning"
NoIcon="true"
ContentAlignment="HorizontalAlignment.Left">
<h5>Never share logs publicly</h5>
Logs might contain sensitive information like your vehicle's location. Do not share logs publicly.
</MudAlert>
<h3>General</h3>

<RightAlignedButtonComponent ButtonText="Download Logs"
StartIcon="@Icons.Material.Filled.Download"
OnButtonClicked="@(_ => NavigationManager.NavigateTo("api/Debug/DownloadLogs", true))"></RightAlignedButtonComponent>

<h3>Car Debug Details</h3>
@if (_debugCars == default)
{
<PlaceholderComponent Count="3"></PlaceholderComponent>
}
else
{
<MudExpansionPanels MultiExpansion="true">
@foreach (var car in _debugCars)
{
<MudExpansionPanel Text="@car.Value.Name">
<div>ID: @car.Key</div>
<div>VIN: @car.Value.Vin</div>
<div>Name: @car.Value.Name</div>
<div>Is Available in Tesla account: @car.Value.IsAvailableInTeslaAccount</div>
<div>Should be managed: @car.Value.ShouldBeManaged</div>


@if (car.Value.Vin != default && _fleetTelemetryGetConfigs.TryGetValue(car.Value.Vin, out var config))
{
<h4>Fleet Telemetry Config</h4>
<pre>@config</pre>
}

<RightAlignedButtonComponent ButtonText="Get Fleet Telemetry Config"
IsLoading="@_isFleetTelemetryLoading"
IsDisabled="@(car.Value.Vin == default || !car.Value.IsAvailableInTeslaAccount)"
DisabledToolTipText="@(car.Value.IsAvailableInTeslaAccount ? null : "Can not check config as car is not part of Tesla account")"
OnButtonClicked="@(() => GetFleetTelemetryConfig(car.Value.Vin))"></RightAlignedButtonComponent>

@if (car.Value.Vin != default && _fleetTelemetrySetResults.TryGetValue(car.Value.Vin, out var result))
{
<h4>Fleet Telemetry SetResult</h4>
<pre>@result</pre>
}

<RightAlignedButtonComponent ButtonText="Normal Fleet Configuration Set"
IsLoading="@_isFleetTelemetryLoading"
IsDisabled="@(car.Value.Vin == default || !car.Value.IsAvailableInTeslaAccount)"
DisabledToolTipText="@(car.Value.IsAvailableInTeslaAccount ? null : "Can not set config as car is not part of Tesla account")"
OnButtonClicked="@(() => SetFleetTelemetryConfig(car.Value.Vin, false))"></RightAlignedButtonComponent>
<RightAlignedButtonComponent ButtonText="Force Fleet Configuration Set"
IsLoading="@_isFleetTelemetryLoading"
IsDisabled="@(car.Value.Vin == default || !car.Value.IsAvailableInTeslaAccount)"
DisabledToolTipText="@(car.Value.IsAvailableInTeslaAccount ? null : "Can not set config as car is not part of Tesla account")"
OnButtonClicked="@(() => SetFleetTelemetryConfig(car.Value.Vin, true))"></RightAlignedButtonComponent>
</MudExpansionPanel>
}
</MudExpansionPanels>
}



@code {
private readonly Dictionary<string, string> _fleetTelemetryGetConfigs = new();

private readonly Dictionary<string, string> _fleetTelemetrySetResults = new();

private Dictionary<int, DtoDebugCar>? _debugCars;

private bool _isFleetTelemetryLoading;


protected override async Task OnInitializedAsync()
{
var cars = await HttpClientHelper.SendGetRequestWithSnackbarAsync<Dictionary<int, DtoDebugCar>>("api/Debug/GetCars");
if (cars != default)
{
_debugCars = cars;
}
}


private async Task GetFleetTelemetryConfig(string? vin)
{
if (vin == default)
{
Snackbar.Add("VIN is unknown", Severity.Error);
return;
}

_isFleetTelemetryLoading = true;
var result = await HttpClientHelper.SendGetRequestAsync<DtoValue<string>>($"api/Debug/GetFleetTelemetryConfiguration?vin={Uri.EscapeDataString(vin)}");
string stringToDisplay;
if (result.HasError)
{
stringToDisplay = result.ErrorMessage ?? "No error message";
}
else
{
stringToDisplay = result.Data?.Value ?? "No data";
}
_fleetTelemetryGetConfigs[vin] = stringToDisplay;
_isFleetTelemetryLoading = false;
}

private async Task SetFleetTelemetryConfig(string? vin, bool forceReconfiguration)
{
if (vin == default)
{
Snackbar.Add("VIN is unknown", Severity.Error);
return;
}

_isFleetTelemetryLoading = true;
var result = await HttpClientHelper.SendPostRequestAsync<DtoValue<string>>($"api/Debug/SetFleetTelemetryConfiguration?vin={Uri.EscapeDataString(vin)}&forceReconfiguration={forceReconfiguration}", null);
string stringToDisplay;
if (result.HasError)
{
stringToDisplay = result.ErrorMessage ?? "No error message";
}
else
{
stringToDisplay = result.Data?.Value ?? "No data";
}
_fleetTelemetrySetResults[vin] = stringToDisplay;
_isFleetTelemetryLoading = false;
}
}
5 changes: 5 additions & 0 deletions TeslaSolarCharger/Client/Shared/NavMenu.razor
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@
<span class="oi oi-cog" aria-hidden="true"></span> Base Configuration
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link px-3" href="support">
<span class="oi oi-code" aria-hidden="true"></span> Support
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link px-3" href="backupAndRestore">
<span class="oi oi-data-transfer-download" aria-hidden="true"></span> Backup and Restore
Expand Down
Loading
Loading