Reduce refresh rate on K2, add refresh rate setting (#117)

* Reduce refresh rate on K2, add refresh rate setting

* Set default k2 update interval to 2s
This commit is contained in:
timklge 2025-05-04 15:15:23 +02:00 committed by GitHub
parent 21d06aab3a
commit c4a23ce456
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 78 additions and 26 deletions

View File

@ -93,11 +93,10 @@ tasks.register("generateManifest") {
"latestVersionCode" to android.defaultConfig.versionCode,
"developer" to "github.com/timklge",
"description" to "Open-source extension that provides headwind direction, wind speed, forecast and other weather data fields.",
"releaseNotes" to "* Fix weather data download from Open-Meteo via iOS companion app (thx @keefar!)\n" +
"releaseNotes" to "* Reduce refresh rate on K2, add refresh rate setting\n" +
"* Fix weather data download from Open-Meteo via iOS companion app (thx @keefar!)\n" +
"* Remove custom wind speed unit setting and always use imperial / metric as set in profile\n" +
"* Add relative grade, relative elevation gain data fields\n" +
"* Fix precipitation forecast field\n" +
"* Interpolate between forecasted and current weather data\n" +
"* Add OpenWeatherMap support contributed by lockevod\n",
"screenshotUrls" to listOf(
"https://github.com/timklge/karoo-headwind/releases/latest/download/preview1.png",

View File

@ -1,6 +1,8 @@
package de.timklge.karooheadwind
import de.timklge.karooheadwind.datatypes.GpsCoordinates
import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.models.HardwareType
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
@ -62,6 +64,30 @@ data class HeadwindStats(
}
enum class RefreshRate(val id: String, val k2Ms: Long, val k3Ms: Long) {
FAST("fast", 1_000L, 500L),
STANDARD("medium", 2_000L, 1_000L),
SLOW("slow", 5_000L, 3_000L),
MINIMUM("minimum", 10_000L, 10_000L);
fun getDescription(karooSystemService: KarooSystemService): String {
return if (karooSystemService.hardwareType == HardwareType.K2) {
when (this) {
FAST -> "Fast (1s)"
STANDARD -> "Standard (2s)"
SLOW -> "Slow (5s)"
MINIMUM -> "Minimum (10s)"
}
} else {
when (this) {
FAST -> "Fastest"
STANDARD -> "Standard (1s)"
SLOW -> "Slow (3s)"
MINIMUM -> "Minimum (10s)"
}
}
}
}
@Serializable
data class HeadwindSettings(
@ -74,7 +100,8 @@ data class HeadwindSettings(
val lastUpdateRequested: Long? = null,
val showDistanceInForecast: Boolean = true,
val weatherProvider: WeatherDataProvider = WeatherDataProvider.OPEN_METEO,
val openWeatherMapApiKey: String = ""
val openWeatherMapApiKey: String = "",
val refreshRate: RefreshRate = RefreshRate.STANDARD,
){
companion object {
val defaultSettings = Json.encodeToString(HeadwindSettings())
@ -85,8 +112,6 @@ data class HeadwindSettings(
}
}
//added openweathermap.org
@Serializable
enum class WeatherDataProvider(val id: String, val label: String) {
OPEN_METEO("open-meteo", "OpenMeteo"),

View File

@ -194,7 +194,7 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
context.streamCurrentForecastWeatherData(),
settingsAndProfileStream,
context.streamWidgetSettings(),
karooSystem.getHeadingFlow(context).throttle(60_000L),
karooSystem.getHeadingFlow(context).throttle(3 * 60_000L),
karooSystem.streamUpcomingRoute().distinctUntilChanged { old, new ->
val oldDistance = old?.distanceAlongRoute
val newDistance = new?.distanceAlongRoute
@ -202,7 +202,7 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
if (oldDistance == null && newDistance == null) return@distinctUntilChanged true
if (oldDistance == null || newDistance == null) return@distinctUntilChanged false
abs(oldDistance - newDistance) < 500
abs(oldDistance - newDistance) < 1_000
}
) { weatherData, settings, widgetSettings, heading, upcomingRoute ->
StreamData(

View File

@ -13,12 +13,14 @@ import de.timklge.karooheadwind.WindDirectionIndicatorSetting
import de.timklge.karooheadwind.getRelativeHeadingFlow
import de.timklge.karooheadwind.streamCurrentWeatherData
import de.timklge.karooheadwind.streamSettings
import de.timklge.karooheadwind.throttle
import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.extension.DataTypeImpl
import io.hammerhead.karooext.internal.Emitter
import io.hammerhead.karooext.internal.ViewEmitter
import io.hammerhead.karooext.models.DataPoint
import io.hammerhead.karooext.models.DataType
import io.hammerhead.karooext.models.HardwareType
import io.hammerhead.karooext.models.StreamState
import io.hammerhead.karooext.models.UpdateGraphicConfig
import io.hammerhead.karooext.models.ViewConfig
@ -29,6 +31,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch
import kotlin.math.roundToInt
@ -139,7 +142,9 @@ class HeadwindDirectionDataType(
}
val viewJob = CoroutineScope(Dispatchers.IO).launch {
flow.collect { streamData ->
val refreshRate = karooSystem.getRefreshRateInMilliseconds(context)
flow.throttle(refreshRate).collect { streamData ->
Log.d(KarooHeadwindExtension.TAG, "Updating headwind direction view")
val errorCode = streamData.bearing.let { if(it < 0) it.toInt() else null }
@ -177,4 +182,15 @@ class HeadwindDirectionDataType(
const val ERROR_NO_WEATHER_DATA = -2
const val ERROR_APP_NOT_SET_UP = -3
}
}
}
suspend fun KarooSystemService.getRefreshRateInMilliseconds(context: Context): Long {
val refreshRate = context.streamSettings(this).first().refreshRate
val isK2 = hardwareType == HardwareType.K2
return if (isK2){
refreshRate.k2Ms
} else {
refreshRate.k3Ms
}
}

View File

@ -23,6 +23,7 @@ import de.timklge.karooheadwind.streamCurrentWeatherData
import de.timklge.karooheadwind.streamDataFlow
import de.timklge.karooheadwind.streamSettings
import de.timklge.karooheadwind.streamUserProfile
import de.timklge.karooheadwind.throttle
import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.extension.DataTypeImpl
import io.hammerhead.karooext.internal.ViewEmitter
@ -73,14 +74,7 @@ class TailwindAndRideSpeedDataType(
) : DataTypeImpl("karoo-headwind", "tailwind-and-ride-speed") {
private val glance = GlanceRemoteViews()
data class StreamData(val headingResponse: HeadingResponse,
val absoluteWindDirection: Double?,
val windSpeed: Double?,
val settings: HeadwindSettings?,
val rideSpeed: Double? = null,
val isImperial: Boolean? = null)
private fun previewFlow(profileFlow: Flow<UserProfile>): Flow<de.timklge.karooheadwind.datatypes.TailwindDataType.StreamData> {
private fun previewFlow(profileFlow: Flow<UserProfile>): Flow<StreamData> {
return flow {
val profile = profileFlow.first()
@ -137,7 +131,8 @@ class TailwindAndRideSpeedDataType(
val viewJob = CoroutineScope(Dispatchers.IO).launch {
emitter.onNext(ShowCustomStreamState("", null))
flow.collect { streamData ->
val refreshRate = karooSystem.getRefreshRateInMilliseconds(context)
flow.throttle(refreshRate).collect { streamData ->
Log.d(KarooHeadwindExtension.TAG, "Updating headwind direction view")
val value = (streamData.headingResponse as? HeadingResponse.Value)?.diff

View File

@ -19,6 +19,7 @@ import de.timklge.karooheadwind.streamCurrentWeatherData
import de.timklge.karooheadwind.streamDataFlow
import de.timklge.karooheadwind.streamSettings
import de.timklge.karooheadwind.streamUserProfile
import de.timklge.karooheadwind.throttle
import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.extension.DataTypeImpl
import io.hammerhead.karooext.internal.ViewEmitter
@ -115,7 +116,8 @@ class TailwindDataType(
val viewJob = CoroutineScope(Dispatchers.IO).launch {
emitter.onNext(ShowCustomStreamState("", null))
flow.collect { streamData ->
val refreshRate = karooSystem.getRefreshRateInMilliseconds(context)
flow.throttle(refreshRate).collect { streamData ->
Log.d(KarooHeadwindExtension.TAG, "Updating tailwind direction view")
val value = (streamData.headingResponse as? HeadingResponse.Value)?.diff

View File

@ -39,11 +39,11 @@ import androidx.compose.ui.window.Dialog
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import de.timklge.karooheadwind.HeadwindSettings
import de.timklge.karooheadwind.KarooHeadwindExtension
import de.timklge.karooheadwind.RefreshRate
import de.timklge.karooheadwind.RoundLocationSetting
import de.timklge.karooheadwind.WeatherDataProvider
import de.timklge.karooheadwind.WindDirectionIndicatorSetting
import de.timklge.karooheadwind.WindDirectionIndicatorTextSetting
import de.timklge.karooheadwind.WindUnit
import de.timklge.karooheadwind.datatypes.GpsCoordinates
import de.timklge.karooheadwind.saveSettings
import de.timklge.karooheadwind.streamSettings
@ -63,6 +63,7 @@ fun SettingsScreen(onFinish: () -> Unit) {
val coroutineScope = rememberCoroutineScope()
val karooSystem = remember { KarooSystemService(ctx) }
var refreshRateSetting by remember { mutableStateOf(RefreshRate.STANDARD) }
var selectedWindDirectionIndicatorTextSetting by remember {
mutableStateOf(
WindDirectionIndicatorTextSetting.HEADWIND_SPEED
@ -73,6 +74,7 @@ fun SettingsScreen(onFinish: () -> Unit) {
WindDirectionIndicatorSetting.HEADWIND_DIRECTION
)
}
var selectedRoundLocationSetting by remember { mutableStateOf(RoundLocationSetting.KM_3) }
var forecastKmPerHour by remember { mutableStateOf("20") }
var forecastMilesPerHour by remember { mutableStateOf("12") }
@ -93,6 +95,7 @@ fun SettingsScreen(onFinish: () -> Unit) {
showDistanceInForecast = settings.showDistanceInForecast
selectedWeatherProvider = settings.weatherProvider
openWeatherMapApiKey = settings.openWeatherMapApiKey
refreshRateSetting = settings.refreshRate
}
}
@ -120,7 +123,8 @@ fun SettingsScreen(onFinish: () -> Unit) {
forecastedKmPerHour = forecastKmPerHour.toIntOrNull()?.coerceIn(5, 50) ?: 20,
showDistanceInForecast = showDistanceInForecast,
weatherProvider = selectedWeatherProvider,
openWeatherMapApiKey = openWeatherMapApiKey
openWeatherMapApiKey = openWeatherMapApiKey,
refreshRate = refreshRateSetting,
)
saveSettings(ctx, newSettings)
@ -147,15 +151,26 @@ fun SettingsScreen(onFinish: () -> Unit) {
.verticalScroll(rememberScrollState())
.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(10.dp)
) {
val refreshRateDropdownOptions = RefreshRate.entries.toList().map { unit -> DropdownOption(unit.id, unit.getDescription(karooSystem)) }
val refreshRateSelection by remember(refreshRateSetting) {
mutableStateOf(refreshRateDropdownOptions.find { option -> option.id == refreshRateSetting.id }!!)
}
Dropdown(
label = "Refresh Rate",
options = refreshRateDropdownOptions,
selected = refreshRateSelection
) { selectedOption ->
refreshRateSetting =
RefreshRate.entries.find { unit -> unit.id == selectedOption.id }!!
}
val windDirectionIndicatorSettingDropdownOptions =
WindDirectionIndicatorSetting.entries.toList()
.map { unit -> DropdownOption(unit.id, unit.label) }
WindDirectionIndicatorSetting.entries.toList().map { unit -> DropdownOption(unit.id, unit.label) }
val windDirectionIndicatorSettingSelection by remember(selectedWindDirectionIndicatorSetting) {
mutableStateOf(windDirectionIndicatorSettingDropdownOptions.find { option -> option.id == selectedWindDirectionIndicatorSetting.id }!!)
}
Dropdown(
label = "Wind direction indicator",
label = "Wind Direction Indicator",
options = windDirectionIndicatorSettingDropdownOptions,
selected = windDirectionIndicatorSettingSelection
) { selectedOption ->
@ -172,7 +187,7 @@ fun SettingsScreen(onFinish: () -> Unit) {
mutableStateOf(windDirectionIndicatorTextSettingDropdownOptions.find { option -> option.id == selectedWindDirectionIndicatorTextSetting.id }!!)
}
Dropdown(
label = "Text on headwind indicator",
label = "Text on Headwind Indicator",
options = windDirectionIndicatorTextSettingDropdownOptions,
selected = windDirectionIndicatorTextSettingSelection
) { selectedOption ->