diff --git a/TeslaSolarCharger/Server/Scheduling/JobManager.cs b/TeslaSolarCharger/Server/Scheduling/JobManager.cs index f31f76a0c..d00212425 100644 --- a/TeslaSolarCharger/Server/Scheduling/JobManager.cs +++ b/TeslaSolarCharger/Server/Scheduling/JobManager.cs @@ -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") diff --git a/TeslaSolarCharger/Server/Services/TeslaFleetApiService.cs b/TeslaSolarCharger/Server/Services/TeslaFleetApiService.cs index 7f084b1fc..2bd67a421 100644 --- a/TeslaSolarCharger/Server/Services/TeslaFleetApiService.cs +++ b/TeslaSolarCharger/Server/Services/TeslaFleetApiService.cs @@ -495,28 +495,53 @@ private async Task 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 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 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 { @@ -548,7 +573,7 @@ private async Task 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; @@ -588,28 +613,31 @@ private async Task IsCarDataRefreshNeeded(DtoCar car) return false; } - private async Task 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 values) + private async Task 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(); + 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 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; @@ -622,14 +650,14 @@ private bool AnyValueChanged(DateTime latestRefresh, List> GetValuesSince(int carId, CarValueType carValueType, DateTime startTime) + private async Task 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 { @@ -641,8 +669,8 @@ private async Task> GetValuesSince(int carId BooleanValue = c.BooleanValue, InvalidValue = c.InvalidValue, }) - .ToListAsync(); - return values; + .FirstOrDefaultAsync(); + return lastBeforeStartTimeValue; } diff --git a/TeslaSolarCharger/Server/appsettings.json b/TeslaSolarCharger/Server/appsettings.json index f0893cfda..4da2bbefa 100644 --- a/TeslaSolarCharger/Server/appsettings.json +++ b/TeslaSolarCharger/Server/appsettings.json @@ -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?",