Skip to content

Commit

Permalink
Merge pull request #1668 from pkuehnel/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
pkuehnel authored Dec 1, 2024
2 parents 09231e2 + e94cf8e commit 81bb282
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 39 deletions.
2 changes: 1 addition & 1 deletion TeslaSolarCharger/Server/Scheduling/JobManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public async Task StartJobs()
.WithSchedule(SimpleScheduleBuilder.RepeatSecondlyForever(59)).Build();

var vehicleDataRefreshTrigger = TriggerBuilder.Create().WithIdentity("vehicleDataRefreshTrigger")
.WithSchedule(SimpleScheduleBuilder.RepeatSecondlyForever(11)).Build();
.WithSchedule(SimpleScheduleBuilder.RepeatSecondlyForever(configurationWrapper.CarRefreshAfterCommandSeconds())).Build();

var teslaMateChargeCostUpdateTrigger = TriggerBuilder.Create()
.WithIdentity("teslaMateChargeCostUpdateTrigger")
Expand Down
102 changes: 65 additions & 37 deletions TeslaSolarCharger/Server/Services/TeslaFleetApiService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -495,28 +495,53 @@ private async Task<bool> IsCarDataRefreshNeeded(DtoCar car)
}
logger.LogDebug("Latest car refresh: {latestRefresh}", latestRefresh);
var currentUtcDate = dateTimeProvider.UtcNow();
var earliestDetectedChange = currentUtcDate.AddSeconds(-configurationWrapper.CarRefreshAfterCommandSeconds());
var latestChangeToDetect = currentUtcDate.AddSeconds(-configurationWrapper.CarRefreshAfterCommandSeconds());
if (fleetTelemetryWebSocketService.IsClientConnected(car.Vin))
{
var latestDetectedChange = latestRefresh.AddSeconds(-configurationWrapper.CarRefreshAfterCommandSeconds());
logger.LogTrace("Fleet Telemetry Client connected, check fleet telemetry changes and do not request Fleet API after commands.");
if (await FleetTelemetryValueChanged(car.Id, CarValueType.IsCharging, latestRefresh, earliestDetectedChange).ConfigureAwait(false))
if (latestRefresh > latestChangeToDetect)
{
logger.LogDebug("Send a request as Fleet Telemetry detected a change in is charging in state.");
return true;
logger.LogDebug("Do not refresh data for car {vin} as latest refresh is {latestRefresh} and earliest change to detect is {earliestChangeToDetect}", car.Vin, latestRefresh, latestChangeToDetect);
}

if (await FleetTelemetryValueChanged(car.Id, CarValueType.IsPluggedIn, latestRefresh, earliestDetectedChange).ConfigureAwait(false))
else
{
logger.LogDebug("Send a request as Fleet Telemetry detected a change in plugged in state.");
return true;
}
if (await FleetTelemetryValueChanged(car.Id, CarValueType.IsCharging, latestDetectedChange, latestChangeToDetect).ConfigureAwait(false))
{
logger.LogDebug("Send a request as Fleet Telemetry detected a change in is charging state.");
return true;
}

var values = await GetValuesSince(car.Id, CarValueType.ChargeAmps, earliestDetectedChange).ConfigureAwait(false);
if (AnyValueChanged(latestRefresh, values) && values.Any(v => v.DoubleValue == 0))
{
logger.LogDebug("Send a request as Fleet Telemetry detected at least one 0 value in charging amps.");
return true;
if (await FleetTelemetryValueChanged(car.Id, CarValueType.IsPluggedIn, latestDetectedChange, latestChangeToDetect).ConfigureAwait(false))
{
logger.LogDebug("Send a request as Fleet Telemetry detected a change in plugged in state.");
return true;
}

var latestValueBeforeLatestRefresh = await GetLatestValueBeforeTimeStamp(car.Id, CarValueType.ChargeAmps, latestDetectedChange).ConfigureAwait(false);
var latestValue = await GetLatestValueBeforeTimeStamp(car.Id, CarValueType.ChargeAmps, latestChangeToDetect).ConfigureAwait(false);
if (latestValue != default && latestValueBeforeLatestRefresh == default)
{
logger.LogDebug("Send a request as the first charging amps value was detected.");
return true;
}

if (latestValue != default && latestValueBeforeLatestRefresh != default)
{
List<CarValueLogTimeStampAndValues> values =
[
latestValue,
latestValueBeforeLatestRefresh,
];
if (AnyValueChanged(values) && values.Any(v => v.DoubleValue == 0))
{
logger.LogDebug("Send a request as Fleet Telemetry detected at least one 0 value in charging amps.");
return true;
}
}

}

}
else
{
Expand Down Expand Up @@ -548,7 +573,7 @@ private async Task<bool> IsCarDataRefreshNeeded(DtoCar car)
logger.LogDebug("Latest command Timestamp: {latestCommandTimeStamp}", latestCommandTimeStamp);

//Do not waste a request if the latest command was in the last few seconds. Request the next time instead
if (latestCommandTimeStamp > earliestDetectedChange)
if (latestCommandTimeStamp > latestChangeToDetect)
{
logger.LogDebug("Do not refresh data as on {latestCommandTimeStamp} there was a command sent to the car.", latestCommandTimeStamp);
return false;
Expand Down Expand Up @@ -588,28 +613,31 @@ private async Task<bool> IsCarDataRefreshNeeded(DtoCar car)
return false;
}

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 bool AnyValueChanged(DateTime latestRefresh, List<CarValueLogTimeStampAndValues> values)
private async Task<bool> FleetTelemetryValueChanged(int carId, CarValueType carValueType, DateTime latestRefresh, DateTime latestChangeToDetect)
{
logger.LogTrace("{method}({latestRefresh}, {@values})", nameof(AnyValueChanged), latestRefresh, values);
// Ensure there are at least two values to compare
if (values.Count < 2)
logger.LogTrace("{method}({carId}, {carValueType}, {latestRefresh}, {latestChangeToDetect})", nameof(FleetTelemetryValueChanged), carId, carValueType, latestRefresh, latestChangeToDetect);
var values = new List<CarValueLogTimeStampAndValues>();
var latestValueBeforeLatestRefresh = await GetLatestValueBeforeTimeStamp(carId, carValueType, latestRefresh).ConfigureAwait(false);
var latestValue = await GetLatestValueBeforeTimeStamp(carId, carValueType, latestChangeToDetect).ConfigureAwait(false);
if (latestValue != default && latestValueBeforeLatestRefresh == default)
{
return false;
//Return true if before the latest refresh there was no value, this is only relevant on new TSC installations
return true;
}

// Check if the latest value is after the latest refresh time
if (values[0].Timestamp <= latestRefresh)
if (latestValueBeforeLatestRefresh != default)
{
return false;
values.Add(latestValueBeforeLatestRefresh);
}
if (latestValue != default)
{
values.Add(latestValue);
}
return AnyValueChanged(values);
}

private bool AnyValueChanged(List<CarValueLogTimeStampAndValues> values)
{
logger.LogTrace("{method}({@values})", nameof(AnyValueChanged), values);
// Check if any of the properties have changed among all values
var doubleValuesChanged = values.Select(v => v.DoubleValue).Distinct().Count() > 1;
var intValuesChanged = values.Select(v => v.IntValue).Distinct().Count() > 1;
Expand All @@ -622,14 +650,14 @@ private bool AnyValueChanged(DateTime latestRefresh, List<CarValueLogTimeStampAn
return doubleValuesChanged || intValuesChanged || stringValuesChanged || unknownValuesChanged || booleanValuesChanged || invalidValuesChanged;
}

private async Task<List<CarValueLogTimeStampAndValues>> GetValuesSince(int carId, CarValueType carValueType, DateTime startTime)
private async Task<CarValueLogTimeStampAndValues?> GetLatestValueBeforeTimeStamp(int carId, CarValueType carValueType, DateTime timestamp)
{
logger.LogTrace("{method}({carId}, {carValueType}, {startTime})", nameof(GetValuesSince), carId, carValueType, startTime);
var values = await teslaSolarChargerContext.CarValueLogs
logger.LogTrace("{method}({carId}, {carValueType}, {timestamp})", nameof(GetLatestValueBeforeTimeStamp), carId, carValueType, timestamp);
var lastBeforeStartTimeValue = await teslaSolarChargerContext.CarValueLogs
.Where(c => c.Type == carValueType
&& c.Source == CarValueSource.FleetTelemetry
&& c.CarId == carId
&& c.Timestamp > startTime)
&& c.Timestamp < timestamp)
.OrderByDescending(c => c.Timestamp)
.Select(c => new CarValueLogTimeStampAndValues
{
Expand All @@ -641,8 +669,8 @@ private async Task<List<CarValueLogTimeStampAndValues>> GetValuesSince(int carId
BooleanValue = c.BooleanValue,
InvalidValue = c.InvalidValue,
})
.ToListAsync();
return values;
.FirstOrDefaultAsync();
return lastBeforeStartTimeValue;
}


Expand Down
3 changes: 2 additions & 1 deletion TeslaSolarCharger/Server/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@
"AwattarBaseUrl": "https://api.awattar.de/v1/marketdata",
"BleBaseUrl": null,
"MaxTravelSpeedMetersPerSecond": 30,
"CarRefreshAfterCommandSeconds": 12,
//This is also the intervall for the car refresh
"CarRefreshAfterCommandSeconds": 11,
"BleUsageStopAfterErrorSeconds": 300,
"FleetApiRefreshIntervalSeconds": 500,
"FleetTelemetryApiUrl": "wss://api.fleet-telemetry.teslasolarcharger.de/ws?",
Expand Down

0 comments on commit 81bb282

Please sign in to comment.