Remove data stream handling for all data types except the primary wind indicator to work around issue in current karoo release (#50)

This commit is contained in:
timklge 2025-02-25 18:22:17 +01:00 committed by GitHub
parent 4dc0eb2364
commit 548b81d7a4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 82 additions and 112 deletions

View File

@ -15,8 +15,8 @@ android {
applicationId = "de.timklge.karooheadwind" applicationId = "de.timklge.karooheadwind"
minSdk = 26 minSdk = 26
targetSdk = 35 targetSdk = 35
versionCode = 12 versionCode = 13
versionName = "1.2.4" versionName = "1.2.5"
} }
signingConfigs { signingConfigs {

View File

@ -3,9 +3,9 @@
"packageName": "de.timklge.karooheadwind", "packageName": "de.timklge.karooheadwind",
"iconUrl": "https://github.com/timklge/karoo-headwind/releases/latest/download/karoo-headwind.png", "iconUrl": "https://github.com/timklge/karoo-headwind/releases/latest/download/karoo-headwind.png",
"latestApkUrl": "https://github.com/timklge/karoo-headwind/releases/latest/download/app-release.apk", "latestApkUrl": "https://github.com/timklge/karoo-headwind/releases/latest/download/app-release.apk",
"latestVersion": "1.2.4", "latestVersion": "1.2.5",
"latestVersionCode": 12, "latestVersionCode": 13,
"developer": "timklge", "developer": "timklge",
"description": "Provides headwind direction, wind speed and other weather data fields", "description": "Provides headwind direction, wind speed and other weather data fields",
"releaseNotes": "Add sealevel pressure data type" "releaseNotes": "Include more directions in wind direction data field, do not use streams for secondary data fields to work around issue in current karoo release"
} }

View File

@ -43,7 +43,7 @@ import kotlin.math.absoluteValue
import kotlin.time.Duration.Companion.hours import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.minutes
class KarooHeadwindExtension : KarooExtension("karoo-headwind", "1.2.4") { class KarooHeadwindExtension : KarooExtension("karoo-headwind", "1.2.5") {
companion object { companion object {
const val TAG = "karoo-headwind" const val TAG = "karoo-headwind"
} }

View File

@ -42,45 +42,51 @@ class HeadwindDirectionDataType(
) : DataTypeImpl("karoo-headwind", "headwind") { ) : DataTypeImpl("karoo-headwind", "headwind") {
private val glance = GlanceRemoteViews() private val glance = GlanceRemoteViews()
override fun startStream(emitter: Emitter<StreamState>) { private fun streamValues(): Flow<Double> = flow {
val job = CoroutineScope(Dispatchers.IO).launch { karooSystem.getRelativeHeadingFlow(applicationContext)
karooSystem.getRelativeHeadingFlow(applicationContext) .combine(applicationContext.streamCurrentWeatherData()) { headingResponse, data -> StreamData(headingResponse, data?.current?.windDirection, data?.current?.windSpeed) }
.combine(applicationContext.streamCurrentWeatherData()) { headingResponse, data -> StreamData(headingResponse, data?.current?.windDirection, data?.current?.windSpeed) } .combine(applicationContext.streamSettings(karooSystem)) { data, settings -> data.copy(settings = settings) }
.combine(applicationContext.streamSettings(karooSystem)) { data, settings -> data.copy(settings = settings) } .collect { streamData ->
.collect { streamData -> val value = (streamData.headingResponse as? HeadingResponse.Value)?.diff
val value = (streamData.headingResponse as? HeadingResponse.Value)?.diff
var returnValue = 0.0 var returnValue = 0.0
if (value == null || streamData.absoluteWindDirection == null || streamData.settings == null || streamData.windSpeed == null){ if (value == null || streamData.absoluteWindDirection == null || streamData.settings == null || streamData.windSpeed == null){
var errorCode = 1.0 var errorCode = 1.0
var headingResponse = streamData.headingResponse var headingResponse = streamData.headingResponse
if (headingResponse is HeadingResponse.Value && (streamData.absoluteWindDirection == null || streamData.windSpeed == null)){ if (headingResponse is HeadingResponse.Value && (streamData.absoluteWindDirection == null || streamData.windSpeed == null)){
headingResponse = HeadingResponse.NoWeatherData headingResponse = HeadingResponse.NoWeatherData
}
if (streamData.settings?.welcomeDialogAccepted == false){
errorCode = ERROR_APP_NOT_SET_UP.toDouble()
} else if (headingResponse is HeadingResponse.NoGps){
errorCode = ERROR_NO_GPS.toDouble()
} else {
errorCode = ERROR_NO_WEATHER_DATA.toDouble()
}
returnValue = errorCode
} else {
var windDirection = when (streamData.settings.windDirectionIndicatorSetting){
WindDirectionIndicatorSetting.HEADWIND_DIRECTION -> value
WindDirectionIndicatorSetting.WIND_DIRECTION -> streamData.absoluteWindDirection + 180
}
if (windDirection < 0) windDirection += 360
returnValue = windDirection
} }
emitter.onNext(StreamState.Streaming(DataPoint(dataTypeId, mapOf(DataType.Field.SINGLE to returnValue)))) if (streamData.settings?.welcomeDialogAccepted == false){
errorCode = ERROR_APP_NOT_SET_UP.toDouble()
} else if (headingResponse is HeadingResponse.NoGps){
errorCode = ERROR_NO_GPS.toDouble()
} else {
errorCode = ERROR_NO_WEATHER_DATA.toDouble()
}
returnValue = errorCode
} else {
var windDirection = when (streamData.settings.windDirectionIndicatorSetting){
WindDirectionIndicatorSetting.HEADWIND_DIRECTION -> value
WindDirectionIndicatorSetting.WIND_DIRECTION -> streamData.absoluteWindDirection + 180
}
if (windDirection < 0) windDirection += 360
returnValue = windDirection
} }
emit(returnValue)
}
}
override fun startStream(emitter: Emitter<StreamState>) {
val job = CoroutineScope(Dispatchers.IO).launch {
streamValues().collect { returnValue ->
emitter.onNext(StreamState.Streaming(DataPoint(dataTypeId, mapOf(DataType.Field.SINGLE to returnValue))))
}
} }
emitter.setCancellable { emitter.setCancellable {
job.cancel() job.cancel()
@ -121,8 +127,8 @@ class HeadwindDirectionDataType(
val flow = if (config.preview) { val flow = if (config.preview) {
previewFlow() previewFlow()
} else { } else {
val directionFlow = karooSystem.streamDataFlow(dataTypeId).mapNotNull { (it as? StreamState.Streaming)?.dataPoint?.singleValue } val directionFlow = streamValues()
val speedFlow = karooSystem.streamDataFlow(DataType.dataTypeId("karoo-headwind", "userwindSpeed")).map { (it as? StreamState.Streaming)?.dataPoint?.singleValue } val speedFlow = UserWindSpeedDataType.streamValues(context, karooSystem)
combine(directionFlow, speedFlow) { direction, speed -> combine(directionFlow, speedFlow) { direction, speed ->
DirectionAndSpeed(direction, speed) DirectionAndSpeed(direction, speed)

View File

@ -24,10 +24,9 @@ import de.timklge.karooheadwind.streamSettings
import de.timklge.karooheadwind.streamUserProfile import de.timklge.karooheadwind.streamUserProfile
import io.hammerhead.karooext.KarooSystemService import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.extension.DataTypeImpl import io.hammerhead.karooext.extension.DataTypeImpl
import io.hammerhead.karooext.internal.Emitter
import io.hammerhead.karooext.internal.ViewEmitter import io.hammerhead.karooext.internal.ViewEmitter
import io.hammerhead.karooext.models.DataPoint
import io.hammerhead.karooext.models.DataType import io.hammerhead.karooext.models.DataType
import io.hammerhead.karooext.models.ShowCustomStreamState
import io.hammerhead.karooext.models.StreamState import io.hammerhead.karooext.models.StreamState
import io.hammerhead.karooext.models.UpdateGraphicConfig import io.hammerhead.karooext.models.UpdateGraphicConfig
import io.hammerhead.karooext.models.UserProfile import io.hammerhead.karooext.models.UserProfile
@ -71,19 +70,6 @@ class TailwindAndRideSpeedDataType(
) : DataTypeImpl("karoo-headwind", "tailwind-and-ride-speed") { ) : DataTypeImpl("karoo-headwind", "tailwind-and-ride-speed") {
private val glance = GlanceRemoteViews() private val glance = GlanceRemoteViews()
override fun startStream(emitter: Emitter<StreamState>) {
val job = CoroutineScope(Dispatchers.IO).launch {
karooSystem.getRelativeHeadingFlow(applicationContext)
.collect { diff ->
val value = (diff as? HeadingResponse.Value)?.diff ?: 0.0
emitter.onNext(StreamState.Streaming(DataPoint(dataTypeId, mapOf(DataType.Field.SINGLE to value))))
}
}
emitter.setCancellable {
job.cancel()
}
}
data class StreamData(val headingResponse: HeadingResponse, data class StreamData(val headingResponse: HeadingResponse,
val absoluteWindDirection: Double?, val absoluteWindDirection: Double?,
val windSpeed: Double?, val windSpeed: Double?,
@ -146,6 +132,8 @@ class TailwindAndRideSpeedDataType(
} }
val viewJob = CoroutineScope(Dispatchers.IO).launch { val viewJob = CoroutineScope(Dispatchers.IO).launch {
emitter.onNext(ShowCustomStreamState("", null))
flow.collect { streamData -> flow.collect { streamData ->
Log.d(KarooHeadwindExtension.TAG, "Updating headwind direction view") Log.d(KarooHeadwindExtension.TAG, "Updating headwind direction view")

View File

@ -16,8 +16,10 @@ import io.hammerhead.karooext.models.DataType
import io.hammerhead.karooext.models.StreamState import io.hammerhead.karooext.models.StreamState
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlin.math.cos import kotlin.math.cos
@ -28,8 +30,8 @@ class UserWindSpeedDataType(
data class StreamData(val headingResponse: HeadingResponse, val weatherResponse: OpenMeteoCurrentWeatherResponse?, val settings: HeadwindSettings) data class StreamData(val headingResponse: HeadingResponse, val weatherResponse: OpenMeteoCurrentWeatherResponse?, val settings: HeadwindSettings)
override fun startStream(emitter: Emitter<StreamState>) { companion object {
val job = CoroutineScope(Dispatchers.IO).launch { fun streamValues(context: Context, karooSystem: KarooSystemService): Flow<Double> = flow {
karooSystem.getRelativeHeadingFlow(context) karooSystem.getRelativeHeadingFlow(context)
.combine(context.streamCurrentWeatherData()) { value, data -> value to data } .combine(context.streamCurrentWeatherData()) { value, data -> value to data }
.combine(context.streamSettings(karooSystem)) { (value, data), settings -> StreamData(value, data, settings) } .combine(context.streamSettings(karooSystem)) { (value, data), settings -> StreamData(value, data, settings) }
@ -41,24 +43,26 @@ class UserWindSpeedDataType(
if (streamData.settings.windDirectionIndicatorTextSetting == WindDirectionIndicatorTextSetting.HEADWIND_SPEED){ if (streamData.settings.windDirectionIndicatorTextSetting == WindDirectionIndicatorTextSetting.HEADWIND_SPEED){
val headwindSpeed = cos((windDirection + 180) * Math.PI / 180.0) * windSpeed val headwindSpeed = cos((windDirection + 180) * Math.PI / 180.0) * windSpeed
emitter.onNext( emit(headwindSpeed)
StreamState.Streaming(
DataPoint(
dataTypeId,
mapOf(DataType.Field.SINGLE to headwindSpeed)
)
)
)
} else { } else {
emitter.onNext( emit(windSpeed)
StreamState.Streaming( }
DataPoint( }
dataTypeId, }
mapOf(DataType.Field.SINGLE to windSpeed) }
)
override fun startStream(emitter: Emitter<StreamState>) {
val job = CoroutineScope(Dispatchers.IO).launch {
streamValues(context, karooSystem)
.collect { value ->
emitter.onNext(
StreamState.Streaming(
DataPoint(
dataTypeId,
mapOf(DataType.Field.SINGLE to value)
) )
) )
} )
} }
} }

View File

@ -28,6 +28,7 @@ import io.hammerhead.karooext.internal.Emitter
import io.hammerhead.karooext.internal.ViewEmitter import io.hammerhead.karooext.internal.ViewEmitter
import io.hammerhead.karooext.models.DataPoint import io.hammerhead.karooext.models.DataPoint
import io.hammerhead.karooext.models.DataType import io.hammerhead.karooext.models.DataType
import io.hammerhead.karooext.models.ShowCustomStreamState
import io.hammerhead.karooext.models.StreamState import io.hammerhead.karooext.models.StreamState
import io.hammerhead.karooext.models.UpdateGraphicConfig import io.hammerhead.karooext.models.UpdateGraphicConfig
import io.hammerhead.karooext.models.UserProfile import io.hammerhead.karooext.models.UserProfile
@ -57,22 +58,6 @@ class WeatherDataType(
val timeFormatter = DateTimeFormatter.ofPattern("HH:mm").withZone(ZoneId.systemDefault()) val timeFormatter = DateTimeFormatter.ofPattern("HH:mm").withZone(ZoneId.systemDefault())
} }
// FIXME: Remove. Currently, the data field will permanently show "no sensor" if no data stream is provided
override fun startStream(emitter: Emitter<StreamState>) {
val job = CoroutineScope(Dispatchers.IO).launch {
val currentWeatherData = applicationContext.streamCurrentWeatherData()
currentWeatherData
.collect { data ->
Log.d(KarooHeadwindExtension.TAG, "Wind code: ${data?.current?.weatherCode}")
emitter.onNext(StreamState.Streaming(DataPoint(dataTypeId, mapOf(DataType.Field.SINGLE to (data?.current?.weatherCode?.toDouble() ?: 0.0)))))
}
}
emitter.setCancellable {
job.cancel()
}
}
data class StreamData(val data: OpenMeteoCurrentWeatherResponse?, val settings: HeadwindSettings, data class StreamData(val data: OpenMeteoCurrentWeatherResponse?, val settings: HeadwindSettings,
val profile: UserProfile? = null, val headingResponse: HeadingResponse? = null) val profile: UserProfile? = null, val headingResponse: HeadingResponse? = null)
@ -113,8 +98,9 @@ class WeatherDataType(
} }
val viewJob = CoroutineScope(Dispatchers.IO).launch { val viewJob = CoroutineScope(Dispatchers.IO).launch {
dataFlow emitter.onNext(ShowCustomStreamState("", null))
.collect { (data, settings, userProfile, headingResponse) ->
dataFlow.collect { (data, settings, userProfile, headingResponse) ->
Log.d(KarooHeadwindExtension.TAG, "Updating weather view") Log.d(KarooHeadwindExtension.TAG, "Updating weather view")
if (data == null){ if (data == null){

View File

@ -45,6 +45,7 @@ import io.hammerhead.karooext.internal.Emitter
import io.hammerhead.karooext.internal.ViewEmitter import io.hammerhead.karooext.internal.ViewEmitter
import io.hammerhead.karooext.models.DataPoint import io.hammerhead.karooext.models.DataPoint
import io.hammerhead.karooext.models.DataType import io.hammerhead.karooext.models.DataType
import io.hammerhead.karooext.models.ShowCustomStreamState
import io.hammerhead.karooext.models.StreamState import io.hammerhead.karooext.models.StreamState
import io.hammerhead.karooext.models.UpdateGraphicConfig import io.hammerhead.karooext.models.UpdateGraphicConfig
import io.hammerhead.karooext.models.UserProfile import io.hammerhead.karooext.models.UserProfile
@ -97,22 +98,6 @@ class WeatherForecastDataType(
val timeFormatter = DateTimeFormatter.ofPattern("HH:mm").withZone(ZoneId.systemDefault()) val timeFormatter = DateTimeFormatter.ofPattern("HH:mm").withZone(ZoneId.systemDefault())
} }
// FIXME: Remove. Currently, the data field will permanently show "no sensor" if no data stream is provided
override fun startStream(emitter: Emitter<StreamState>) {
val job = CoroutineScope(Dispatchers.IO).launch {
val currentWeatherData = applicationContext.streamCurrentWeatherData()
currentWeatherData
.collect { data ->
Log.d(KarooHeadwindExtension.TAG, "Wind code: ${data?.current?.weatherCode}")
emitter.onNext(StreamState.Streaming(DataPoint(dataTypeId, mapOf(DataType.Field.SINGLE to (data?.current?.weatherCode?.toDouble() ?: 0.0)))))
}
}
emitter.setCancellable {
job.cancel()
}
}
data class StreamData(val data: OpenMeteoCurrentWeatherResponse?, val settings: HeadwindSettings, data class StreamData(val data: OpenMeteoCurrentWeatherResponse?, val settings: HeadwindSettings,
val widgetSettings: HeadwindWidgetSettings? = null, val profile: UserProfile? = null, val headingResponse: HeadingResponse? = null) val widgetSettings: HeadwindWidgetSettings? = null, val profile: UserProfile? = null, val headingResponse: HeadingResponse? = null)
@ -167,6 +152,8 @@ class WeatherForecastDataType(
} }
val viewJob = CoroutineScope(Dispatchers.IO).launch { val viewJob = CoroutineScope(Dispatchers.IO).launch {
emitter.onNext(ShowCustomStreamState("", null))
dataFlow.collect { (data, settings, widgetSettings, userProfile, headingResponse) -> dataFlow.collect { (data, settings, widgetSettings, userProfile, headingResponse) ->
Log.d(KarooHeadwindExtension.TAG, "Updating weather forecast view") Log.d(KarooHeadwindExtension.TAG, "Updating weather forecast view")

View File

@ -21,6 +21,7 @@ import de.timklge.karooheadwind.OpenMeteoCurrentWeatherResponse
import de.timklge.karooheadwind.streamDataFlow import de.timklge.karooheadwind.streamDataFlow
import io.hammerhead.karooext.KarooSystemService import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.internal.ViewEmitter import io.hammerhead.karooext.internal.ViewEmitter
import io.hammerhead.karooext.models.ShowCustomStreamState
import io.hammerhead.karooext.models.StreamState import io.hammerhead.karooext.models.StreamState
import io.hammerhead.karooext.models.UpdateGraphicConfig import io.hammerhead.karooext.models.UpdateGraphicConfig
import io.hammerhead.karooext.models.ViewConfig import io.hammerhead.karooext.models.ViewConfig
@ -69,6 +70,8 @@ class WindDirectionDataType(val karooSystem: KarooSystemService, context: Contex
} }
val viewJob = CoroutineScope(Dispatchers.IO).launch { val viewJob = CoroutineScope(Dispatchers.IO).launch {
emitter.onNext(ShowCustomStreamState("", null))
val flow = if (config.preview){ val flow = if (config.preview){
previewFlow() previewFlow()
} else { } else {
@ -77,10 +80,6 @@ class WindDirectionDataType(val karooSystem: KarooSystemService, context: Contex
} }
flow flow
.onCompletion {
val result = glance.compose(context, DpSize.Unspecified) { }
emitter.updateView(result.remoteViews)
}
.collect { windBearing -> .collect { windBearing ->
val windCardinalDirectionIndex = ((windBearing % 360) / 22.5).roundToInt() % 16 val windCardinalDirectionIndex = ((windBearing % 360) / 22.5).roundToInt() % 16