Skip to content

Commit

Permalink
Merge pull request #1662 from pkuehnel/feat/logging
Browse files Browse the repository at this point in the history
feat(chore): improve fleet telemetry logging
  • Loading branch information
pkuehnel authored Nov 26, 2024
2 parents bc3cbeb + 9f30ab6 commit de3c778
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 91 deletions.
180 changes: 91 additions & 89 deletions TeslaSolarCharger/Server/Services/FleetTelemetryWebSocketService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,10 @@ public async Task ReconnectWebSocketsForEnabledCars()
var segment = new ArraySegment<byte>(bytesToSend);
try
{
logger.LogDebug("Sending Heartbeat to websocket client for car {vin}", existingClient.Vin);
await existingClient.WebSocketClient.SendAsync(segment, WebSocketMessageType.Text, true,
new CancellationTokenSource(_heartbeatsendTimeout).Token);
logger.LogDebug("Heartbeat to websocket client for car {vin} sent", existingClient.Vin);
}
catch (Exception ex)
{
Expand All @@ -69,11 +71,10 @@ await existingClient.WebSocketClient.SendAsync(segment, WebSocketMessageType.Tex

continue;
}
else
{
existingClient.WebSocketClient.Dispose();
Clients.Remove(existingClient);
}

logger.LogInformation("Websocket Client for car {vin} is not open. Disposing client", car.Vin);
existingClient.WebSocketClient.Dispose();
Clients.Remove(existingClient);
}

ConnectToFleetTelemetryApi(car.Vin, car.UseFleetTelemetryForLocationData);
Expand Down Expand Up @@ -158,14 +159,16 @@ await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing",

private async Task ReceiveMessages(ClientWebSocket webSocket, CancellationToken ctx, string vin, int carId)
{
logger.LogTrace("{method}(webSocket, ctx, {vin}, {carId})", nameof(ReceiveMessages), vin, carId);
var buffer = new byte[1024 * 4]; // Buffer to store incoming data
while (webSocket.State == WebSocketState.Open)
{
try
{
// Receive message from the WebSocket server
logger.LogTrace("Waiting for new fleet telemetry message for car {vin}", vin);
var result = await webSocket.ReceiveAsync(new(buffer), ctx);

logger.LogTrace("Received new fleet telemetry message for car {vin}", vin);
if (result.MessageType == WebSocketMessageType.Close)
{
// If the server closed the connection, close the WebSocket
Expand All @@ -183,96 +186,95 @@ private async Task ReceiveMessages(ClientWebSocket webSocket, CancellationToken
}

var message = DeserializeFleetTelemetryMessage(jsonMessage);
if (message != null)
if (message == default)
{
if (configurationWrapper.LogLocationData() ||
(message.Type != CarValueType.Latitude && message.Type != CarValueType.Longitude))
{
logger.LogDebug("Save fleet telemetry message {@message}", message);
}
else
logger.LogWarning("Could not deserialize non heartbeat message {string}", jsonMessage);
continue;
}

if (configurationWrapper.LogLocationData() ||
(message.Type != CarValueType.Latitude && message.Type != CarValueType.Longitude))
{
logger.LogDebug("Save fleet telemetry message {@message}", message);
}
else
{
logger.LogDebug("Save location message for car {carId}", carId);
}

var scope = serviceProvider.CreateScope();
var context = scope.ServiceProvider.GetRequiredService<TeslaSolarChargerContext>();
var carValueLog = new CarValueLog
{
CarId = carId,
Type = message.Type,
DoubleValue = message.DoubleValue,
IntValue = message.IntValue,
StringValue = message.StringValue,
UnknownValue = message.UnknownValue,
BooleanValue = message.BooleanValue,
InvalidValue = message.InvalidValue,
Timestamp = message.TimeStamp.UtcDateTime,
Source = CarValueSource.FleetTelemetry,
};
context.CarValueLogs.Add(carValueLog);
await context.SaveChangesAsync().ConfigureAwait(false);
if (configurationWrapper.GetVehicleDataFromTesla())
{
var settingsCar = settings.Cars.First(c => c.Vin == vin);
string? propertyName = null;
switch (message.Type)
{
logger.LogDebug("Save location message for car {carId}", carId);
case CarValueType.ChargeAmps:
propertyName = nameof(DtoCar.ChargerActualCurrent);
break;
case CarValueType.ChargeCurrentRequest:
propertyName = nameof(DtoCar.ChargerRequestedCurrent);
break;
case CarValueType.IsPluggedIn:
propertyName = nameof(DtoCar.PluggedIn);
break;
case CarValueType.IsCharging:
if (carValueLog.BooleanValue == true && settingsCar.State != CarStateEnum.Charging)
{
logger.LogDebug("Set car state for car {carId} to charging", carId);
settingsCar.State = CarStateEnum.Charging;
}
else if (carValueLog.BooleanValue == false && settingsCar.State == CarStateEnum.Charging)
{
logger.LogDebug("Set car state for car {carId} to online", carId);
settingsCar.State = CarStateEnum.Online;
}
break;
case CarValueType.ChargerPilotCurrent:
propertyName = nameof(DtoCar.ChargerPilotCurrent);
break;
case CarValueType.Longitude:
propertyName = nameof(DtoCar.Longitude);
break;
case CarValueType.Latitude:
propertyName = nameof(DtoCar.Latitude);
break;
case CarValueType.StateOfCharge:
propertyName = nameof(DtoCar.SoC);
break;
case CarValueType.StateOfChargeLimit:
propertyName = nameof(DtoCar.SocLimit);
break;
case CarValueType.ChargerPhases:
propertyName = nameof(DtoCar.SocLimit);
break;
case CarValueType.ChargerVoltage:
propertyName = nameof(DtoCar.ChargerVoltage);
break;
}

var scope = serviceProvider.CreateScope();
var context = scope.ServiceProvider.GetRequiredService<TeslaSolarChargerContext>();
var carValueLog = new CarValueLog
if (propertyName != default)
{
CarId = carId,
Type = message.Type,
DoubleValue = message.DoubleValue,
IntValue = message.IntValue,
StringValue = message.StringValue,
UnknownValue = message.UnknownValue,
BooleanValue = message.BooleanValue,
InvalidValue = message.InvalidValue,
Timestamp = message.TimeStamp.UtcDateTime,
Source = CarValueSource.FleetTelemetry,
};
context.CarValueLogs.Add(carValueLog);
await context.SaveChangesAsync().ConfigureAwait(false);
if (configurationWrapper.GetVehicleDataFromTesla())
{
var settingsCar = settings.Cars.First(c => c.Vin == vin);
string? propertyName = null;
switch (message.Type)
{
case CarValueType.ChargeAmps:
propertyName = nameof(DtoCar.ChargerActualCurrent);
break;
case CarValueType.ChargeCurrentRequest:
propertyName = nameof(DtoCar.ChargerRequestedCurrent);
break;
case CarValueType.IsPluggedIn:
propertyName = nameof(DtoCar.PluggedIn);
break;
case CarValueType.IsCharging:
if (carValueLog.BooleanValue == true && settingsCar.State != CarStateEnum.Charging)
{
logger.LogDebug("Set car state for car {carId} to charging", carId);
settingsCar.State = CarStateEnum.Charging;
}
else if (carValueLog.BooleanValue == false && settingsCar.State == CarStateEnum.Charging)
{
logger.LogDebug("Set car state for car {carId} to online", carId);
settingsCar.State = CarStateEnum.Online;
}
break;
case CarValueType.ChargerPilotCurrent:
propertyName = nameof(DtoCar.ChargerPilotCurrent);
break;
case CarValueType.Longitude:
propertyName = nameof(DtoCar.Longitude);
break;
case CarValueType.Latitude:
propertyName = nameof(DtoCar.Latitude);
break;
case CarValueType.StateOfCharge:
propertyName = nameof(DtoCar.SoC);
break;
case CarValueType.StateOfChargeLimit:
propertyName = nameof(DtoCar.SocLimit);
break;
case CarValueType.ChargerPhases:
propertyName = nameof(DtoCar.SocLimit);
break;
case CarValueType.ChargerVoltage:
propertyName = nameof(DtoCar.ChargerVoltage);
break;
}

if (propertyName != default)
{
UpdateDtoCarProperty(settingsCar, carValueLog, propertyName);
}
UpdateDtoCarProperty(settingsCar, carValueLog, propertyName);
}

}
else
{
logger.LogWarning("Could not deserialize non heartbeat message {string}", jsonMessage);
}

}
}
catch (Exception ex)
Expand Down
6 changes: 4 additions & 2 deletions TeslaSolarCharger/Server/Services/TeslaFleetApiService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -590,13 +590,14 @@ private async Task<bool> IsCarDataRefreshNeeded(DtoCar car)

private async Task<bool> FleetTelemetryValueChanged(int carId, CarValueType carValueType, DateTime latestRefresh, DateTime currentUtcDate)
{
logger.LogTrace("{method}({carId}, {carValueType}, {latestRefresh}, {currentUtcDate})", nameof(FleetTelemetryValueChanged), carId, carValueType, latestRefresh, currentUtcDate);
var values = await GetValuesSince(carId, carValueType, currentUtcDate.AddSeconds(-configurationWrapper.CarRefreshAfterCommandSeconds())).ConfigureAwait(false);

return AnyValueChanged(latestRefresh, values);
}

private static bool AnyValueChanged(DateTime latestRefresh, List<CarValueLogTimeStampAndValues> values)
private bool AnyValueChanged(DateTime latestRefresh, List<CarValueLogTimeStampAndValues> values)
{
logger.LogTrace("{method}({latestRefresh}, {@values})", nameof(AnyValueChanged), latestRefresh, values);
// Ensure there are at least two values to compare
if (values.Count < 2)
{
Expand All @@ -623,6 +624,7 @@ private static bool AnyValueChanged(DateTime latestRefresh, List<CarValueLogTime

private async Task<List<CarValueLogTimeStampAndValues>> GetValuesSince(int carId, CarValueType carValueType, DateTime startTime)
{
logger.LogTrace("{method}({carId}, {carValueType}, {startTime})", nameof(GetValuesSince), carId, carValueType, startTime);
var values = await teslaSolarChargerContext.CarValueLogs
.Where(c => c.Type == carValueType
&& c.Source == CarValueSource.FleetTelemetry
Expand Down

0 comments on commit de3c778

Please sign in to comment.