fix #21: Save last known gps position
This commit is contained in:
parent
407755e94b
commit
a662cc6757
@ -48,9 +48,8 @@ import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.filterNot
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.mapNotNull
|
||||
import kotlinx.coroutines.flow.scan
|
||||
import kotlinx.coroutines.flow.single
|
||||
import kotlinx.coroutines.flow.timeout
|
||||
@ -68,6 +67,7 @@ val settingsKey = stringPreferencesKey("settings")
|
||||
val widgetSettingsKey = stringPreferencesKey("widgetSettings")
|
||||
val currentDataKey = stringPreferencesKey("current")
|
||||
val statsKey = stringPreferencesKey("stats")
|
||||
val lastKnownPositionKey = stringPreferencesKey("lastKnownPosition")
|
||||
|
||||
suspend fun saveSettings(context: Context, settings: HeadwindSettings) {
|
||||
context.dataStore.edit { t ->
|
||||
@ -93,6 +93,18 @@ suspend fun saveCurrentData(context: Context, forecast: OpenMeteoCurrentWeatherR
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun saveLastKnownPosition(context: Context, gpsCoordinates: GpsCoordinates) {
|
||||
Log.i(KarooHeadwindExtension.TAG, "Saving last known position: $gpsCoordinates")
|
||||
|
||||
try {
|
||||
context.dataStore.edit { t ->
|
||||
t[lastKnownPositionKey] = Json.encodeToString(gpsCoordinates)
|
||||
}
|
||||
} catch(e: Throwable){
|
||||
Log.e(KarooHeadwindExtension.TAG, "Failed to save last known position", e)
|
||||
}
|
||||
}
|
||||
|
||||
fun KarooSystemService.streamDataFlow(dataTypeId: String): Flow<StreamState> {
|
||||
return callbackFlow {
|
||||
val listenerId = addConsumer(OnStreamState.StartStreaming(dataTypeId)) { event: OnStreamState ->
|
||||
@ -194,6 +206,22 @@ fun Context.streamStats(): Flow<HeadwindStats> {
|
||||
}.distinctUntilChanged()
|
||||
}
|
||||
|
||||
suspend fun Context.getLastKnownPosition(): GpsCoordinates? {
|
||||
val settingsJson = dataStore.data.first()
|
||||
|
||||
try {
|
||||
val lastKnownPositionString = settingsJson[lastKnownPositionKey] ?: return null
|
||||
val lastKnownPosition = jsonWithUnknownKeys.decodeFromString<GpsCoordinates>(
|
||||
lastKnownPositionString
|
||||
)
|
||||
|
||||
return lastKnownPosition
|
||||
} catch(e: Throwable){
|
||||
Log.e(KarooHeadwindExtension.TAG, "Failed to read last known position", e)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
fun KarooSystemService.streamUserProfile(): Flow<UserProfile> {
|
||||
return callbackFlow {
|
||||
val listenerId = addConsumer { userProfile: UserProfile ->
|
||||
@ -268,7 +296,7 @@ sealed class HeadingResponse {
|
||||
fun KarooSystemService.getRelativeHeadingFlow(context: Context): Flow<HeadingResponse> {
|
||||
val currentWeatherData = context.streamCurrentWeatherData()
|
||||
|
||||
return getHeadingFlow()
|
||||
return getHeadingFlow(context)
|
||||
.combine(currentWeatherData) { bearing, data -> bearing to data }
|
||||
.map { (bearing, data) ->
|
||||
when {
|
||||
@ -287,13 +315,12 @@ fun KarooSystemService.getRelativeHeadingFlow(context: Context): Flow<HeadingRes
|
||||
}
|
||||
}
|
||||
|
||||
fun KarooSystemService.getHeadingFlow(): Flow<HeadingResponse> {
|
||||
fun KarooSystemService.getHeadingFlow(context: Context): Flow<HeadingResponse> {
|
||||
// return flowOf(HeadingResponse.Value(20.0))
|
||||
|
||||
return streamDataFlow(DataType.Type.LOCATION)
|
||||
.map { (it as? StreamState.Streaming)?.dataPoint?.values }
|
||||
.map { values ->
|
||||
val heading = values?.get(DataType.Field.LOC_BEARING)
|
||||
return getGpsCoordinateFlow(context)
|
||||
.map { coords ->
|
||||
val heading = coords?.bearing
|
||||
Log.d(KarooHeadwindExtension.TAG, "Updated gps bearing: $heading")
|
||||
val headingValue = heading?.let { HeadingResponse.Value(it) }
|
||||
|
||||
@ -318,24 +345,56 @@ fun KarooSystemService.getHeadingFlow(): Flow<HeadingResponse> {
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> concatenate(vararg flows: Flow<T>) = flow {
|
||||
var hadNullValue = false
|
||||
|
||||
for (flow in flows) {
|
||||
flow.collect { value ->
|
||||
if (!hadNullValue) {
|
||||
emit(value)
|
||||
if (value == null) hadNullValue = true
|
||||
} else {
|
||||
if (value != null) emit(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(FlowPreview::class)
|
||||
suspend fun KarooSystemService.updateLastKnownGps(context: Context) {
|
||||
getGpsCoordinateFlow(context)
|
||||
.filterNotNull()
|
||||
.throttle(60 * 1_000) // Only update last known gps position once every minute
|
||||
.collect { gps ->
|
||||
saveLastKnownPosition(context, gps)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(FlowPreview::class)
|
||||
fun KarooSystemService.getGpsCoordinateFlow(context: Context): Flow<GpsCoordinates?> {
|
||||
// return flowOf(GpsCoordinates(52.5164069,13.3784))
|
||||
|
||||
return streamDataFlow(DataType.Type.LOCATION)
|
||||
val initialFlow = flow<GpsCoordinates> { context.getLastKnownPosition() }
|
||||
|
||||
val gpsFlow = streamDataFlow(DataType.Type.LOCATION)
|
||||
.map { (it as? StreamState.Streaming)?.dataPoint?.values }
|
||||
.map { values ->
|
||||
val lat = values?.get(DataType.Field.LOC_LATITUDE)
|
||||
val lon = values?.get(DataType.Field.LOC_LONGITUDE)
|
||||
val bearing = values?.get(DataType.Field.LOC_BEARING)
|
||||
|
||||
if (lat != null && lon != null){
|
||||
Log.d(KarooHeadwindExtension.TAG, "Updated gps coordinates: $lat $lon")
|
||||
GpsCoordinates(lat, lon)
|
||||
GpsCoordinates(lat, lon, bearing)
|
||||
} else {
|
||||
Log.w(KarooHeadwindExtension.TAG, "Gps unavailable: $values")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
val concatenatedFlow = concatenate(initialFlow, gpsFlow)
|
||||
|
||||
return concatenatedFlow
|
||||
.combine(context.streamSettings(this)) { gps, settings -> gps to settings }
|
||||
.map { (gps, settings) ->
|
||||
val rounded = gps?.round(settings.roundLocationTo.km.toDouble())
|
||||
|
||||
@ -40,8 +40,10 @@ class KarooHeadwindExtension : KarooExtension("karoo-headwind", "1.1.3") {
|
||||
const val TAG = "karoo-headwind"
|
||||
}
|
||||
|
||||
|
||||
lateinit var karooSystem: KarooSystemService
|
||||
|
||||
private var updateLastKnownGpsJob: Job? = null
|
||||
private var serviceJob: Job? = null
|
||||
|
||||
override val types by lazy {
|
||||
@ -71,6 +73,10 @@ class KarooHeadwindExtension : KarooExtension("karoo-headwind", "1.1.3") {
|
||||
|
||||
karooSystem = KarooSystemService(applicationContext)
|
||||
|
||||
updateLastKnownGpsJob = CoroutineScope(Dispatchers.IO).launch {
|
||||
karooSystem.updateLastKnownGps(this@KarooHeadwindExtension)
|
||||
}
|
||||
|
||||
serviceJob = CoroutineScope(Dispatchers.IO).launch {
|
||||
karooSystem.connect { connected ->
|
||||
if (connected) {
|
||||
|
||||
16
app/src/main/kotlin/de/timklge/karooheadwind/Throttle.kt
Normal file
16
app/src/main/kotlin/de/timklge/karooheadwind/Throttle.kt
Normal file
@ -0,0 +1,16 @@
|
||||
package de.timklge.karooheadwind
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
||||
fun<T> Flow<T>.throttle(timeout: Long): Flow<T> = flow {
|
||||
var lastEmissionTime = 0L
|
||||
|
||||
collect { value ->
|
||||
val currentTime = System.currentTimeMillis()
|
||||
if (currentTime - lastEmissionTime >= timeout) {
|
||||
emit(value)
|
||||
lastEmissionTime = currentTime
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,7 +9,7 @@ import kotlin.math.sin
|
||||
import kotlin.math.sqrt
|
||||
|
||||
@Serializable
|
||||
data class GpsCoordinates(val lat: Double, val lon: Double){
|
||||
data class GpsCoordinates(val lat: Double, val lon: Double, val bearing: Double? = 0.0){
|
||||
companion object {
|
||||
private fun roundDegrees(degrees: Double, km: Double): Double {
|
||||
val nkm = degrees * 111
|
||||
|
||||
@ -66,10 +66,9 @@ class WeatherDataType(
|
||||
val currentWeatherData = applicationContext.streamCurrentWeatherData()
|
||||
|
||||
currentWeatherData
|
||||
.filterNotNull()
|
||||
.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()))))
|
||||
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 {
|
||||
@ -96,7 +95,7 @@ class WeatherDataType(
|
||||
context.streamCurrentWeatherData()
|
||||
.combine(context.streamSettings(karooSystem)) { data, settings -> StreamData(data, settings) }
|
||||
.combine(karooSystem.streamUserProfile()) { data, profile -> data.copy(profile = profile) }
|
||||
.combine(karooSystem.getHeadingFlow()) { data, heading -> data.copy(headingResponse = heading) }
|
||||
.combine(karooSystem.getHeadingFlow(context)) { data, heading -> data.copy(headingResponse = heading) }
|
||||
.collect { (data, settings, userProfile, headingResponse) ->
|
||||
Log.d(KarooHeadwindExtension.TAG, "Updating weather view")
|
||||
|
||||
|
||||
@ -126,7 +126,7 @@ class WeatherForecastDataType(
|
||||
.combine(context.streamSettings(karooSystem)) { data, settings -> StreamData(data, settings) }
|
||||
.combine(karooSystem.streamUserProfile()) { data, profile -> data.copy(profile = profile) }
|
||||
.combine(context.streamWidgetSettings()) { data, widgetSettings -> data.copy(widgetSettings = widgetSettings) }
|
||||
.combine(karooSystem.getHeadingFlow()) { data, headingResponse -> data.copy(headingResponse = headingResponse) }
|
||||
.combine(karooSystem.getHeadingFlow(context)) { data, headingResponse -> data.copy(headingResponse = headingResponse) }
|
||||
.collect { (data, settings, widgetSettings, userProfile, headingResponse) ->
|
||||
Log.d(KarooHeadwindExtension.TAG, "Updating weather forecast view")
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user