Skip to content

Commit

Permalink
Merge pull request #1680 from pkuehnel/feat/handleFleetTelemetryError…
Browse files Browse the repository at this point in the history
…Messages

feat(FleetTelemetryWebSocketService): can handle error messages
  • Loading branch information
pkuehnel authored Dec 7, 2024
2 parents 551cd0a + 60030cf commit 281a667
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace TeslaSolarCharger.Server.Dtos.FleetTelemetry;

public class DtoFleetTelemetryErrorMessage
{
public List<string> MissingKeyVins { get; set; } = new List<string>();
public List<string> UnsupportedHardwareVins { get; set; } = new List<string>();
public List<string> UnsupportedFirmwareVins { get; set; } = new List<string>();
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using TeslaSolarCharger.Shared.Enums;

namespace TeslaSolarCharger.Server.Dtos;
namespace TeslaSolarCharger.Server.Dtos.FleetTelemetry;

public class DtoTscFleetTelemetryMessage
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using TeslaSolarCharger.Server.Enums;

namespace TeslaSolarCharger.Server.Dtos.FleetTelemetry;

public class FleetTelemetryMessageBase
{
public FleetTelemetryMessageType MessageType { get; set; }
}
7 changes: 7 additions & 0 deletions TeslaSolarCharger/Server/Enums/FleetTelemetryMessageType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace TeslaSolarCharger.Server.Enums;

public enum FleetTelemetryMessageType
{
Telemetry,
Error,
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Globalization;
using System.Net.WebSockets;
using System.Text;
using TeslaSolarCharger.Model.Entities.TeslaSolarCharger;
using TeslaSolarCharger.Model.EntityFramework;
using TeslaSolarCharger.Server.Dtos;
using TeslaSolarCharger.Server.Dtos.FleetTelemetry;
using TeslaSolarCharger.Server.Enums;
using TeslaSolarCharger.Server.Helper;
using TeslaSolarCharger.Server.Services.Contracts;
using TeslaSolarCharger.Shared.Contracts;
Expand Down Expand Up @@ -39,7 +42,9 @@ public async Task ReconnectWebSocketsForEnabledCars()
var scope = serviceProvider.CreateScope();
var context = scope.ServiceProvider.GetRequiredService<TeslaSolarChargerContext>();
var cars = await context.Cars
.Where(c => c.UseFleetTelemetry && (c.ShouldBeManaged == true))
.Where(c => c.UseFleetTelemetry
&& (c.ShouldBeManaged == true)
&& (c.TeslaFleetApiState != TeslaCarFleetApiState.NotWorking))
.Select(c => new { c.Vin, c.UseFleetTelemetryForLocationData, })
.ToListAsync();
var bytesToSend = Encoding.UTF8.GetBytes("Heartbeat");
Expand Down Expand Up @@ -194,14 +199,24 @@ private async Task ReceiveMessages(DtoFleetTelemetryWebSocketClients client, str
client.LastReceivedHeartbeat = dateTimeProvider.UtcNow();
continue;
}
logger.LogTrace("Received non heartbeate message.");
logger.LogTrace("Received non heartbeat message.");
var jObject = JObject.Parse(jsonMessage);
var messageType = jObject[nameof(FleetTelemetryMessageBase.MessageType)]?.ToObject<FleetTelemetryMessageType>();
if (messageType == FleetTelemetryMessageType.Error)
{
var couldHandleErrorMessage = await HandleErrorMessage(jsonMessage);
if (!couldHandleErrorMessage)
{
logger.LogWarning("Could not deserialize non heartbeat message {string}", jsonMessage);
}
continue;
}
var message = DeserializeFleetTelemetryMessage(jsonMessage);
if (message == default)
{
logger.LogWarning("Could not deserialize non heartbeat message {string}", jsonMessage);
continue;
}

if (configurationWrapper.LogLocationData() ||
(message.Type != CarValueType.Latitude && message.Type != CarValueType.Longitude))
{
Expand Down Expand Up @@ -294,6 +309,58 @@ private async Task ReceiveMessages(DtoFleetTelemetryWebSocketClients client, str
}
}

private async Task<bool> HandleErrorMessage(string jsonMessage)
{
logger.LogTrace("{method}({jsonMessage}", nameof(HandleErrorMessage), jsonMessage);
var message = JsonConvert.DeserializeObject<DtoFleetTelemetryErrorMessage>(jsonMessage);
if(message == default)
{
return false;
}
foreach (var vin in message.MissingKeyVins)
{
var scope = serviceProvider.CreateScope();
var context = scope.ServiceProvider.GetRequiredService<TeslaSolarChargerContext>();
var car = context.Cars.FirstOrDefault(c => c.Vin == vin);
if (car == default)
{
continue;
}
logger.LogInformation("Set Fleet API state for car {vin} to not working", vin);
car.TeslaFleetApiState = TeslaCarFleetApiState.NotWorking;
await context.SaveChangesAsync();
}

foreach (var vin in message.UnsupportedFirmwareVins)
{
logger.LogInformation("Disable Fleet Telemetry for car {vin} as firmware is not supported", vin);
await DisableFleetTelemetryForCar(vin).ConfigureAwait(false);
}

foreach (var vin in message.UnsupportedHardwareVins)
{
logger.LogInformation("Disable Fleet Telemetry for car {vin} as hardware is not supported", vin);
await DisableFleetTelemetryForCar(vin).ConfigureAwait(false);
}

return true;
}

private async Task DisableFleetTelemetryForCar(string vin)
{
logger.LogTrace("{method}({vin})", nameof(DisableFleetTelemetryForCar), vin);
var scope = serviceProvider.CreateScope();
var context = scope.ServiceProvider.GetRequiredService<TeslaSolarChargerContext>();
var car = context.Cars.FirstOrDefault(c => c.Vin == vin);
if (car == default)
{
return;
}
car.UseFleetTelemetry = false;
car.UseFleetTelemetryForLocationData = false;
await context.SaveChangesAsync();
}

internal DtoTscFleetTelemetryMessage? DeserializeFleetTelemetryMessage(string jsonMessage)
{
var settings = new JsonSerializerSettings
Expand Down
2 changes: 1 addition & 1 deletion TeslaSolarCharger/Shared/Dtos/CarBasicConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public CarBasicConfiguration(int id, string? name)
public bool UseBle { get; set; }
[HelperText("Needed to send commands via BLE to the car. An example value would be `http://raspible:7210/`")]
public string? BleApiBaseUrl { get; set; }
[HelperText("Only supported on cars with Software 2024.38.2+. Not supported on Pre 2021 Model S/X. If enabled, some data will be transferred via Fleet Telemetry. This improves the delay in the TSC detection of plugin and out of the car, as well as changes in the charging speed. Note: All data transferred via Fleet Telemetry passes my server.")]
[HelperText("Only supported on cars with Software 2024.38.2+. Not supported on Pre 2021 Model S/X. If enabled, some data will be transferred via Fleet Telemetry. This improves the delay in the TSC detection of plugin and out of the car, as well as changes in the charging speed. Note: All data transferred via Fleet Telemetry passes my server. If your car does not support fleet telemetry, this option will be disabled automatically within two minutes.")]
public bool UseFleetTelemetry { get; set; }

[HelperText("This further improves the detection if the car is at home. Enabling this results in additionally streaming the field Location over my server. If you do not mind that your car location data passes my server, do not disable this option.")]
Expand Down

0 comments on commit 281a667

Please sign in to comment.