Throttle volume commands to prevent ESP32 overload

Limits volume API calls to max 1 per 300ms while dragging the slider.
UI updates remain immediate for smooth feedback, and the final value
is always sent when the user stops adjusting.
This commit is contained in:
Pavel Baksy 2025-11-22 23:48:54 +01:00
parent 947cff4867
commit db9796bf29

View File

@ -47,9 +47,13 @@ class MainViewModel @Inject constructor(
private var pollingJob: Job? = null private var pollingJob: Job? = null
private var lastStationName: String? = null private var lastStationName: String? = null
private var connectionFailedSince: Long? = null private var connectionFailedSince: Long? = null
private var volumeJob: Job? = null
private var lastVolumeSentTime: Long = 0
private var pendingVolume: Int? = null
companion object { companion object {
private const val ERROR_DISPLAY_DELAY_MS = 10_000L // 10 seconds private const val ERROR_DISPLAY_DELAY_MS = 10_000L // 10 seconds
private const val VOLUME_THROTTLE_MS = 300L // Throttle volume commands
} }
init { init {
@ -161,15 +165,35 @@ class MainViewModel @Inject constructor(
} }
fun setVolume(volume: Int) { fun setVolume(volume: Int) {
viewModelScope.launch { val serverAddress = _uiState.value.serverAddress
val serverAddress = _uiState.value.serverAddress if (serverAddress.isBlank()) return
if (serverAddress.isBlank()) return@launch
// Optimistically update UI // Always update UI immediately for smooth feedback
_uiState.update { _uiState.update {
it.copy(karadioStatus = it.karadioStatus.copy(volume = volume)) it.copy(karadioStatus = it.karadioStatus.copy(volume = volume))
}
// Throttle network calls
val now = System.currentTimeMillis()
pendingVolume = volume
if (now - lastVolumeSentTime >= VOLUME_THROTTLE_MS) {
// Enough time has passed, send immediately
sendVolumeToDevice(serverAddress, volume)
} else {
// Schedule a delayed send for the pending value
volumeJob?.cancel()
volumeJob = viewModelScope.launch {
delay(VOLUME_THROTTLE_MS - (now - lastVolumeSentTime))
pendingVolume?.let { sendVolumeToDevice(serverAddress, it) }
} }
}
}
private fun sendVolumeToDevice(serverAddress: String, volume: Int) {
lastVolumeSentTime = System.currentTimeMillis()
pendingVolume = null
viewModelScope.launch {
karadioRepository.setVolume(serverAddress, volume) karadioRepository.setVolume(serverAddress, volume)
} }
} }