Skip to content

Commit

Permalink
feat(TeslaFleetApiService): check licenses
Browse files Browse the repository at this point in the history
  • Loading branch information
pkuehnel committed Jan 16, 2025
1 parent a9ec1d7 commit 17f7e40
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,7 @@ public interface IIssueKeys
string FleetApiTokenExpired { get; }
string Solar4CarSideFleetApiNonSuccessStatusCode { get; }
string BackendTokenNotRefreshable { get; }
string BaseAppNotLicensed { get; }
string FleetApiNotLicensed { get; }
string FleetTelemetryNotConnected { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,8 @@ public class IssueKeys : IIssueKeys
public string BackendTokenUnauthorized => "BackendTokenUnauthorized";
public string BackendTokenNotRefreshable => "BackendTokenNotRefreshable";
public string FleetApiTokenExpired => "FleetApiTokenExpired";
public string BaseAppNotLicensed => "BaseAppNotLicensed";
public string FleetApiNotLicensed => "FleetApiNotLicensed";
public string FleetTelemetryNotConnected => "FleetTelemetryNotConnected";
}

Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,33 @@ public class PossibleIssues(IIssueKeys issueKeys) : IPossibleIssues
HideOccurrenceCount = true,
}
},
{ issueKeys.BaseAppNotLicensed, new DtoIssue
{
IssueSeverity = IssueSeverity.Error,
IsTelegramEnabled = true,
ShowErrorAfterOccurrences = 1,
HasPlaceHolderIssueKey = false,
HideOccurrenceCount = true,
}
},
{ issueKeys.FleetApiNotLicensed, new DtoIssue
{
IssueSeverity = IssueSeverity.Error,
IsTelegramEnabled = true,
ShowErrorAfterOccurrences = 1,
HasPlaceHolderIssueKey = false,
HideOccurrenceCount = true,
}
},
{ issueKeys.FleetTelemetryNotConnected, new DtoIssue
{
IssueSeverity = IssueSeverity.Error,
IsTelegramEnabled = true,
ShowErrorAfterOccurrences = 1,
HasPlaceHolderIssueKey = false,
HideOccurrenceCount = true,
}
},
};

public DtoIssue GetIssueByKey(string key)
Expand Down
21 changes: 20 additions & 1 deletion TeslaSolarCharger/Server/Services/ErrorHandlingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public class ErrorHandlingService(ILogger<ErrorHandlingService> logger,
ISettings settings,
ITokenHelper tokenHelper,
IPossibleIssues possibleIssues,
IConstants constants) : IErrorHandlingService
IConstants constants,
IFleetTelemetryWebSocketService fleetTelemetryWebSocketService) : IErrorHandlingService
{
public async Task<Fin<List<DtoLoggedError>>> GetActiveLoggedErrors()
{
Expand Down Expand Up @@ -137,6 +138,10 @@ await AddOrRemoveErrors(activeErrors, issueKeys.SolarValuesNotAvailable, "Solar
await AddOrRemoveErrors(activeErrors, issueKeys.VersionNotUpToDate, "New software version available",
"Update TSC to the latest version.", settings.IsNewVersionAvailable).ConfigureAwait(false);

//ToDO: fix next line, currently not working due to cyclic reference
//await AddOrRemoveErrors(activeErrors, issueKeys.BaseAppNotLicensed, "Base App not licensed",
// "Can not send commands to car as app is not licensed", !await backendApiService.IsBaseAppLicensed(true));

//ToDo: if last check there was no token related issue, only detect token related issues every x minutes as creates high load in backend
await DetectTokenStateIssues(activeErrors);
foreach (var car in settings.CarsToManage)
Expand All @@ -153,6 +158,20 @@ await AddOrRemoveErrors(activeErrors, issueKeys.VersionNotUpToDate, "New softwar
//ToDo: In a future release this should only be done if no fleet api request was sent the last x minutes (BleUsageStopAfterError)
await HandleErrorResolved(issueKeys.UsingFleetApiAsBleFallback, car.Vin);
}
var fleetTelemetryEnabled = await context.Cars
.Where(c => c.Vin == car.Vin)
.Select(c => c.UseFleetTelemetry)
.FirstOrDefaultAsync();

if (fleetTelemetryEnabled && (!fleetTelemetryWebSocketService.IsClientConnected(car.Vin)))
{
await HandleError(nameof(ErrorHandlingService), nameof(DetectErrors), $"Fleet Telemetry not connected for car {car.Vin}",
"Fleet telemetry is not connected. Please check the connection.", issueKeys.FleetTelemetryNotConnected, car.Vin, null);
}
else
{
await HandleErrorResolved(issueKeys.FleetTelemetryNotConnected, car.Vin);
}

if (car.State is CarStateEnum.Asleep or CarStateEnum.Offline)
{
Expand Down
46 changes: 38 additions & 8 deletions TeslaSolarCharger/Server/Services/TeslaFleetApiService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,16 @@ private async Task WakeUpCarIfNeeded(int carId)
private async Task<DtoGenericTeslaResponse<T>?> SendCommandToTeslaApi<T>(string vin, DtoFleetApiRequest fleetApiRequest, int? intParam = null) where T : class
{
logger.LogTrace("{method}({vin}, {@fleetApiRequest}, {intParam})", nameof(SendCommandToTeslaApi), vin, fleetApiRequest, intParam);
if (!await backendApiService.IsBaseAppLicensed(true))
{
logger.LogError("Can not send request to car as base app is not licensed");
await errorHandlingService.HandleError(nameof(TeslaFleetApiService), nameof(SendCommandToTeslaApi), "Base App not licensed",
"Can not send commands to car as app is not licensed",
issueKeys.BaseAppNotLicensed, null, null).ConfigureAwait(false);
return null;
}
await errorHandlingService.HandleErrorResolved(issueKeys.BaseAppNotLicensed, null);

var car = settings.Cars.First(c => c.Vin == vin);
if (fleetApiRequest.BleCompatible)
{
Expand Down Expand Up @@ -897,19 +907,39 @@ private async Task WakeUpCarIfNeeded(int carId)
await errorHandlingService.HandleError(nameof(TeslaFleetApiService), nameof(SendCommandToTeslaApi), $"Error sending BLE command for car {car.Vin}",
$"Sending command to tesla via BLE did not succeed. Fleet API URL would be: {fleetApiRequest.RequestUrl}. BLE Response: {result.ResultMessage}",
issueKeys.BleCommandNoSuccess + fleetApiRequest.RequestUrl, car.Vin, null).ConfigureAwait(false);
car.LastNonSuccessBleCall = dateTimeProvider.UtcNow();
var fallbackUntilLocalTimeString =
(car.LastNonSuccessBleCall + configurationWrapper.BleUsageStopAfterError()).Value.ToLocalTime();
logger.LogWarning("Command BLE enabled but command did not succeed, using Fleet API as fallback until {fallbackUntil}.", fallbackUntilLocalTimeString);
await errorHandlingService.HandleError(nameof(TeslaFleetApiService), nameof(SendCommandToTeslaApi),
$"Using Fleet API as BLE fallback for car {car.Vin}",
$"As the BLE command did not succeed, Fleet API is used as fallback until {fallbackUntilLocalTimeString}. Note: During this time it is not possible to retry BLE automatically you need to go to the car settings page and test BLE access manually.",
issueKeys.UsingFleetApiAsBleFallback, car.Vin, null).ConfigureAwait(false);
if (await backendApiService.IsFleetApiLicensed(car.Vin, true))
{
car.LastNonSuccessBleCall = dateTimeProvider.UtcNow();
var fallbackUntilLocalTimeString =
(car.LastNonSuccessBleCall + configurationWrapper.BleUsageStopAfterError()).Value.ToLocalTime();
logger.LogWarning("Command BLE enabled but command did not succeed, using Fleet API as fallback until {fallbackUntil}.", fallbackUntilLocalTimeString);
await errorHandlingService.HandleError(nameof(TeslaFleetApiService), nameof(SendCommandToTeslaApi),
$"Using Fleet API as BLE fallback for car {car.Vin}",
$"As the BLE command did not succeed, Fleet API is used as fallback until {fallbackUntilLocalTimeString}. Note: During this time it is not possible to retry BLE automatically you need to go to the car settings page and test BLE access manually.",
issueKeys.UsingFleetApiAsBleFallback, car.Vin, null).ConfigureAwait(false);
}
else
{
//Do not use Fleet API if not licensed
logger.LogInformation("Do not use Fleet API as Fallback as Fleet API is not licensed for car {vin}", car.Vin);
return null;
}

}

}
}

if (!await backendApiService.IsFleetApiLicensed(car.Vin, true))
{
await errorHandlingService.HandleError(nameof(TeslaFleetApiService), nameof(SendCommandToTeslaApi), $"Fleet API not licensed for car {car.Vin}",
"Can not send Fleet API commands to car as Fleet API is not licensed",
issueKeys.FleetApiNotLicensed, car.Vin, null).ConfigureAwait(false);
logger.LogError("Can not send Fleet API commands to car {vin} as car is not licensed", car.Vin);
return null;
}
await errorHandlingService.HandleErrorResolved(issueKeys.FleetApiNotLicensed, car.Vin);

var accessToken = await teslaSolarChargerContext.BackendTokens.SingleOrDefaultAsync();
if (accessToken == default)
{
Expand Down

0 comments on commit 17f7e40

Please sign in to comment.