Compare commits

...

5 Commits

Author SHA1 Message Date
a8f7f53d66 Remove apk archival step
All checks were successful
Build / build (push) Successful in 5m37s
2025-05-30 13:31:44 +02:00
823fe3a8bb Update pipeline
Some checks failed
Build / build (push) Failing after 9m14s
2025-05-30 13:13:29 +02:00
522364dd84 Unit conversions
Some checks failed
Build / build (push) Failing after 34s
2025-05-29 15:24:52 +02:00
855ce46b99 ref #136: Fix cloud cover, surface level pressure, sealevel pressure and relative humidity are not included in forecast values 2025-05-24 11:51:53 +02:00
0332e032d4 Refactor unit conversion 2025-05-24 11:51:53 +02:00
33 changed files with 259 additions and 157 deletions

View File

@ -3,10 +3,10 @@ name: Build
on:
workflow_dispatch:
push:
branches: [ "master" ]
branches: [ "**" ]
tags: [ "*" ]
pull_request:
branches: [ "master" ]
branches: [ "**" ]
jobs:
build:
@ -19,13 +19,14 @@ jobs:
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
- name: Set up environment variables
run: |
echo "GPR_USER=${{ github.actor }}" >> $GITHUB_ENV
echo "GPR_KEY=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV
echo "GPR_USER=${{ secrets.GHUB_USER || github.actor }}" >> $GITHUB_ENV
echo "GPR_KEY=${{ secrets.GHUB_TOKEN || secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV
echo "KEY_ALIAS=${{ secrets.KEY_ALIAS }}" >> $GITHUB_ENV
echo "KEY_PASSWORD=${{ secrets.KEY_PASSWORD }}" >> $GITHUB_ENV
echo "KEYSTORE_PASSWORD=${{ secrets.KEYSTORE_PASSWORD }}" >> $GITHUB_ENV
echo "KEYSTORE_BASE64=${{ secrets.KEYSTORE_BASE64 }}" >> $GITHUB_ENV
echo "BUILD_NUMBER=${{ github.run_number }}" >> $GITHUB_ENV
echo "BASE_URL=${{ secrets.BASE_URL || 'https://github.com/timklge/karoo-headwind/releases/latest/download' }}" >> $GITHUB_ENV
- uses: actions/checkout@v4
- name: set up JDK 17
uses: actions/setup-java@v4
@ -34,25 +35,30 @@ jobs:
distribution: 'temurin'
cache: gradle
- name: Setup Android SDK
uses: android-actions/setup-android@v3
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew build
- name: Archive APK
uses: actions/upload-artifact@v4
with:
name: app-release.apk
path: app/build/outputs/apk/release/app-release.apk
- name: Create Release
id: create_release
uses: ncipollo/release-action@v1
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
with:
name: ${{ github.ref_name }}
prerelease: false
generateReleaseNotes: true
artifacts: app/build/outputs/apk/release/app-release.apk, app/manifest.json, app/karoo-headwind.png, preview0.png, preview1.png, preview2.png, preview3.png
draft: false
generate_release_notes: true
make_latest: true
files: |
app/build/outputs/apk/release/app-release.apk
app/manifest.json
app/karoo-headwind.png
preview0.png
preview1.png
preview2.png
preview3.png
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

1
.gitignore vendored
View File

@ -9,3 +9,4 @@
.cxx
local.properties
/app/release
app/manifest.json

View File

@ -1,3 +1,4 @@
import com.android.build.gradle.tasks.ProcessApplicationManifest
import java.util.Base64
plugins {
@ -60,29 +61,38 @@ tasks.register("generateManifest") {
group = "build"
doLast {
val baseUrl = System.getenv("BASE_URL") ?: "https://github.com/timklge/karoo-headwind/releases/latest/download"
val manifestFile = file("$projectDir/manifest.json")
val manifest = mapOf(
"label" to "Headwind",
"packageName" to "de.timklge.karooheadwind",
"iconUrl" to "https://github.com/timklge/karoo-headwind/releases/latest/download/karoo-headwind.png",
"latestApkUrl" to "https://github.com/timklge/karoo-headwind/releases/latest/download/app-release.apk",
"iconUrl" to "$baseUrl/karoo-headwind.png",
"latestApkUrl" to "$baseUrl/app-release.apk",
"latestVersion" to android.defaultConfig.versionName,
"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 "* Remove crashlytics\n" +
"releaseNotes" to "* Refactor unit conversions\n* Remove crashlytics\n" +
"* Reduce refresh rate on K2, add refresh rate setting\n" +
"screenshotUrls" to listOf(
"https://github.com/timklge/karoo-headwind/releases/latest/download/preview1.png",
"https://github.com/timklge/karoo-headwind/releases/latest/download/preview3.png",
"https://github.com/timklge/karoo-headwind/releases/latest/download/preview2.png",
"https://github.com/timklge/karoo-headwind/releases/latest/download/preview0.png",
"$baseUrl/preview1.png",
"$baseUrl/preview3.png",
"$baseUrl/preview2.png",
"$baseUrl/preview0.png",
)
)
val gson = groovy.json.JsonBuilder(manifest).toPrettyString()
manifestFile.writeText(gson)
println("Generated manifest.json with version ${android.defaultConfig.versionName} (${android.defaultConfig.versionCode})")
if (System.getenv()["BASE_URL"] != null){
val androidManifestFile = file("$projectDir/src/main/AndroidManifest.xml")
var androidManifestContent = androidManifestFile.readText()
androidManifestContent = androidManifestContent.replace("\$BASE_URL\$", baseUrl)
androidManifestFile.writeText(androidManifestContent)
println("Replaced \$BASE_URL$ in AndroidManifest.xml")
}
}
}
@ -90,6 +100,12 @@ tasks.named("assemble") {
dependsOn("generateManifest")
}
tasks.withType<ProcessApplicationManifest>().configureEach {
if (name == "processDebugMainManifest" || name == "processReleaseMainManifest") {
dependsOn(tasks.named("generateManifest"))
}
}
dependencies {
implementation(libs.mapbox.sdk.turf)
implementation(libs.hammerhead.karoo.ext)

View File

@ -32,6 +32,6 @@
<meta-data
android:name="io.hammerhead.karooext.MANIFEST_URL"
android:value="https://github.com/timklge/karoo-headwind/releases/latest/download/manifest.json" />
android:value="$BASE_URL$/manifest.json" />
</application>
</manifest>

View File

@ -210,6 +210,22 @@ fun Context.streamCurrentForecastWeatherData(): Flow<WeatherDataResponse?> {
}.distinctUntilChanged()
}
fun lerp(
start: Double,
end: Double,
factor: Double
): Double {
return start + (end - start) * factor
}
fun lerp(
start: Int,
end: Int,
factor: Double
): Int {
return (start + (end - start) * factor).toInt()
}
fun lerpNullable(
start: Double?,
end: Double?,
@ -266,12 +282,12 @@ fun lerpWeather(
return WeatherData(
time = (start.time + (end.time - start.time) * factor).toLong(),
temperature = start.temperature + (end.temperature - start.temperature) * factor,
relativeHumidity = lerpNullable(start.relativeHumidity, end.relativeHumidity, factor),
relativeHumidity = lerp(start.relativeHumidity, end.relativeHumidity, factor),
precipitation = start.precipitation + (end.precipitation - start.precipitation) * factor,
precipitationProbability = lerpNullable(start.precipitationProbability, end.precipitationProbability, factor),
cloudCover = lerpNullable(start.cloudCover, end.cloudCover, factor),
surfacePressure = lerpNullable(start.surfacePressure, end.surfacePressure, factor),
sealevelPressure = lerpNullable(start.sealevelPressure, end.sealevelPressure, factor),
cloudCover = lerp(start.cloudCover, end.cloudCover, factor),
surfacePressure = lerp(start.surfacePressure, end.surfacePressure, factor),
sealevelPressure = lerp(start.sealevelPressure, end.sealevelPressure, factor),
windSpeed = start.windSpeed + (end.windSpeed - start.windSpeed) * factor,
windDirection = lerpAngle(start.windDirection, end.windDirection, factor),
windGusts = start.windGusts + (end.windGusts - start.windGusts) * factor,

View File

@ -4,16 +4,23 @@ import android.content.Context
import android.util.Log
import de.timklge.karooheadwind.KarooHeadwindExtension
import de.timklge.karooheadwind.streamCurrentWeatherData
import de.timklge.karooheadwind.streamUserProfile
import de.timklge.karooheadwind.throttle
import de.timklge.karooheadwind.weatherprovider.WeatherData
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.StreamState
import io.hammerhead.karooext.models.UpdateGraphicConfig
import io.hammerhead.karooext.models.UserProfile
import io.hammerhead.karooext.models.ViewConfig
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.launch
@ -22,20 +29,25 @@ abstract class BaseDataType(
private val applicationContext: Context,
dataTypeId: String
) : DataTypeImpl("karoo-headwind", dataTypeId) {
abstract fun getValue(data: WeatherData): Double?
abstract fun getValue(data: WeatherData, userProfile: UserProfile): Double?
open fun getFormatDataType(): String? = null
override fun startStream(emitter: Emitter<StreamState>) {
Log.d(KarooHeadwindExtension.TAG, "start $dataTypeId stream")
val job = CoroutineScope(Dispatchers.IO).launch {
val currentWeatherData = applicationContext.streamCurrentWeatherData(karooSystemService)
data class StreamData(val weatherData: WeatherData, val userProfile: UserProfile)
val currentWeatherData = combine(applicationContext.streamCurrentWeatherData(karooSystemService).filterNotNull(), karooSystemService.streamUserProfile()) { weatherData, userProfile ->
StreamData(weatherData, userProfile)
}
val refreshRate = karooSystemService.getRefreshRateInMilliseconds(applicationContext)
currentWeatherData
.filterNotNull()
currentWeatherData.filterNotNull()
.throttle(refreshRate)
.collect { data ->
val value = getValue(data)
.collect { (data, userProfile) ->
val value = getValue(data, userProfile)
Log.d(KarooHeadwindExtension.TAG, "$dataTypeId: $value")
if (value != null) {
@ -50,4 +62,12 @@ abstract class BaseDataType(
job.cancel()
}
}
override fun startView(context: Context, config: ViewConfig, emitter: ViewEmitter) {
Log.d(KarooHeadwindExtension.TAG, "Starting $dataTypeId view with $emitter")
if (getFormatDataType() != null){
emitter.onNext(UpdateGraphicConfig(formatDataTypeId = getFormatDataType()))
}
}
}

View File

@ -3,9 +3,10 @@ package de.timklge.karooheadwind.datatypes
import android.content.Context
import de.timklge.karooheadwind.weatherprovider.WeatherData
import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.models.UserProfile
class CloudCoverDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "cloudCover"){
override fun getValue(data: WeatherData): Double? {
override fun getValue(data: WeatherData, userProfile: UserProfile): Double? {
return data.cloudCover
}
}

View File

@ -37,6 +37,9 @@ import de.timklge.karooheadwind.streamUpcomingRoute
import de.timklge.karooheadwind.streamUserProfile
import de.timklge.karooheadwind.streamWidgetSettings
import de.timklge.karooheadwind.throttle
import de.timklge.karooheadwind.util.celciusInUserUnit
import de.timklge.karooheadwind.util.millimetersInUserUnit
import de.timklge.karooheadwind.util.msInUserUnit
import de.timklge.karooheadwind.weatherprovider.WeatherData
import de.timklge.karooheadwind.weatherprovider.WeatherDataForLocation
import de.timklge.karooheadwind.weatherprovider.WeatherDataResponse
@ -116,7 +119,7 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
WeatherData(
time = forecastTime,
temperature = forecastTemperature,
relativeHumidity = 20.0,
relativeHumidity = 20,
precipitation = forecastPrecipitation,
cloudCover = 3.0,
sealevelPressure = 1013.25,
@ -139,7 +142,7 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
current = WeatherData(
time = timeAtFullHour,
temperature = 20.0,
relativeHumidity = 20.0,
relativeHumidity = 20,
precipitation = 0.0,
cloudCover = 3.0,
sealevelPressure = 1013.25,
@ -311,11 +314,11 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
arrowBitmap = baseBitmap,
current = interpretation,
windBearing = data.current.windDirection.roundToInt(),
windSpeed = data.current.windSpeed.roundToInt(),
windGusts = data.current.windGusts.roundToInt(),
precipitation = data.current.precipitation,
windSpeed = msInUserUnit(data.current.windSpeed, settingsAndProfile.isImperial).roundToInt(),
windGusts = msInUserUnit(data.current.windGusts, settingsAndProfile.isImperial).roundToInt(),
precipitation = millimetersInUserUnit(data.current.precipitation, settingsAndProfile.isImperial),
precipitationProbability = null,
temperature = data.current.temperature.roundToInt(),
temperature = celciusInUserUnit(data.current.temperature, settingsAndProfile.isImperialTemperature).roundToInt(),
temperatureUnit = if (settingsAndProfile.isImperialTemperature) TemperatureUnit.FAHRENHEIT else TemperatureUnit.CELSIUS,
timeLabel = formattedTime,
dateLabel = if (hasNewDate) formattedDate else null,
@ -337,11 +340,11 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
arrowBitmap = baseBitmap,
current = interpretation,
windBearing = weatherData?.windDirection?.roundToInt() ?: 0,
windSpeed = weatherData?.windSpeed?.roundToInt() ?: 0,
windGusts = weatherData?.windGusts?.roundToInt() ?: 0,
precipitation = weatherData?.precipitation ?: 0.0,
windSpeed = msInUserUnit(weatherData?.windSpeed ?: 0.0, settingsAndProfile.isImperial).roundToInt(),
windGusts = msInUserUnit(weatherData?.windGusts ?: 0.0, settingsAndProfile.isImperial).roundToInt(),
precipitation = millimetersInUserUnit(weatherData?.precipitation ?: 0.0, settingsAndProfile.isImperial),
precipitationProbability = weatherData?.precipitationProbability?.toInt(),
temperature = weatherData?.temperature?.roundToInt() ?: 0,
temperature = celciusInUserUnit(weatherData?.temperature ?: 0.0, settingsAndProfile.isImperialTemperature).roundToInt(),
temperatureUnit = if (settingsAndProfile.isImperialTemperature) TemperatureUnit.FAHRENHEIT else TemperatureUnit.CELSIUS,
timeLabel = formattedTime,
dateLabel = if (hasNewDate) formattedDate else null,

View File

@ -44,7 +44,6 @@ fun GraphicalForecast(
provider = ImageProvider(getWeatherIcon(current, isNight)),
contentDescription = "Current weather information",
contentScale = ContentScale.Fit,
colorFilter = ColorFilter.tint(ColorProvider(Color.Black, Color.White))
)
}

View File

@ -14,7 +14,9 @@ import de.timklge.karooheadwind.getRelativeHeadingFlow
import de.timklge.karooheadwind.streamCurrentWeatherData
import de.timklge.karooheadwind.streamDatatypeIsVisible
import de.timklge.karooheadwind.streamSettings
import de.timklge.karooheadwind.streamUserProfile
import de.timklge.karooheadwind.throttle
import de.timklge.karooheadwind.util.msInUserUnit
import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.extension.DataTypeImpl
import io.hammerhead.karooext.internal.Emitter
@ -24,6 +26,7 @@ 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.UserProfile
import io.hammerhead.karooext.models.ViewConfig
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@ -63,7 +66,7 @@ class HeadwindDirectionDataType(
val value = (streamData.headingResponse as? HeadingResponse.Value)?.diff
var returnValue = 0.0
if (value == null || streamData.absoluteWindDirection == null || streamData.settings == null || streamData.windSpeed == null){
if (value == null || streamData.absoluteWindDirection == null || streamData.windSpeed == null){
var errorCode = 1.0
var headingResponse = streamData.headingResponse
@ -71,7 +74,7 @@ class HeadwindDirectionDataType(
headingResponse = HeadingResponse.NoWeatherData
}
if (streamData.settings?.welcomeDialogAccepted == false){
if (streamData.settings.welcomeDialogAccepted == false){
errorCode = ERROR_APP_NOT_SET_UP.toDouble()
} else if (headingResponse is HeadingResponse.NoGps){
errorCode = ERROR_NO_GPS.toDouble()
@ -106,7 +109,12 @@ class HeadwindDirectionDataType(
}
}
data class DirectionAndSpeed(val bearing: Double, val speed: Double?, val isVisible: Boolean)
data class DirectionAndSpeed(
val bearing: Double,
val speed: Double?,
val isVisible: Boolean,
val isImperial: Boolean
)
private fun previewFlow(): Flow<DirectionAndSpeed> {
return flow {
@ -114,7 +122,12 @@ class HeadwindDirectionDataType(
val bearing = (0..360).random().toDouble()
val windSpeed = (0..20).random()
emit(DirectionAndSpeed(bearing, windSpeed.toDouble(), true))
emit(DirectionAndSpeed(
bearing,
windSpeed.toDouble(),
true,
true
))
delay(2_000)
}
@ -144,8 +157,8 @@ class HeadwindDirectionDataType(
emitAll(UserWindSpeedDataType.streamValues(context, karooSystem))
}
combine(directionFlow, speedFlow, karooSystem.streamDatatypeIsVisible(dataTypeId)) { direction, speed, isVisible ->
DirectionAndSpeed(direction, speed, isVisible)
combine(directionFlow, speedFlow, karooSystem.streamDatatypeIsVisible(dataTypeId), karooSystem.streamUserProfile()) { direction, speed, isVisible, profile ->
DirectionAndSpeed(direction, speed, isVisible, profile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL)
}
}
@ -162,14 +175,15 @@ class HeadwindDirectionDataType(
}
val windDirection = streamData.bearing
val windSpeed = streamData.speed
val windSpeed = streamData.speed ?: 0.0
val windSpeedUserUnit = msInUserUnit(windSpeed, streamData.isImperial)
val result = glance.compose(context, DpSize.Unspecified) {
HeadwindDirection(
baseBitmap,
windDirection.roundToInt(),
config.textSize,
windSpeed?.toInt()?.toString() ?: "",
windSpeedUserUnit.roundToInt().toString(),
preview = config.preview,
wideMode = false
)

View File

@ -11,9 +11,12 @@ 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.StreamState
import io.hammerhead.karooext.models.UpdateGraphicConfig
import io.hammerhead.karooext.models.ViewConfig
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.combine
@ -49,5 +52,9 @@ class HeadwindSpeedDataType(
job.cancel()
}
}
override fun startView(context: Context, config: ViewConfig, emitter: ViewEmitter) {
emitter.onNext(UpdateGraphicConfig(formatDataTypeId = DataType.Type.SPEED))
}
}

View File

@ -1,11 +1,13 @@
package de.timklge.karooheadwind.datatypes
import android.content.Context
import de.timklge.karooheadwind.util.millimetersInUserUnit
import de.timklge.karooheadwind.weatherprovider.WeatherData
import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.models.UserProfile
class PrecipitationDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "precipitation"){
override fun getValue(data: WeatherData): Double {
return data.precipitation
override fun getValue(data: WeatherData, userProfile: UserProfile): Double {
return millimetersInUserUnit(data.precipitation, userProfile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL)
}
}

View File

@ -129,30 +129,9 @@ class RelativeGradeDataType(private val karooSystemService: KarooSystemService,
val refreshRate = karooSystemService.getRefreshRateInMilliseconds(context)
val windSpeedFlow = combine(context.streamSettings(karooSystemService), karooSystemService.streamUserProfile(), context.streamCurrentWeatherData(karooSystemService).filterNotNull()) { settings, profile, weatherData ->
val isOpenMeteo = settings.weatherProvider == WeatherDataProvider.OPEN_METEO
val profileIsImperial = profile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL
if (isOpenMeteo) {
if (profileIsImperial) { // OpenMeteo returns wind speed in mph
val windSpeedInMilesPerHour = weatherData.windSpeed
windSpeedInMilesPerHour * 0.44704
} else { // Wind speed reported by openmeteo is in km/h
val windSpeedInKmh = weatherData.windSpeed
windSpeedInKmh * 0.277778
}
} else {
if (profileIsImperial) { // OpenWeatherMap returns wind speed in mph
val windSpeedInMilesPerHour = weatherData.windSpeed
windSpeedInMilesPerHour * 0.44704
} else { // Wind speed reported by openweathermap is in m/s
val windSpeedFlow = context.streamCurrentWeatherData(karooSystemService).filterNotNull().map { weatherData ->
weatherData.windSpeed
}
}
}
data class StreamValues(
val relativeWindDirection: Double,

View File

@ -3,9 +3,10 @@ package de.timklge.karooheadwind.datatypes
import android.content.Context
import de.timklge.karooheadwind.weatherprovider.WeatherData
import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.models.UserProfile
class RelativeHumidityDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "relativeHumidity"){
override fun getValue(data: WeatherData): Double? {
return data.relativeHumidity
override fun getValue(data: WeatherData, userProfile: UserProfile): Double? {
return data.relativeHumidity.toDouble()
}
}

View File

@ -3,9 +3,10 @@ package de.timklge.karooheadwind.datatypes
import android.content.Context
import de.timklge.karooheadwind.weatherprovider.WeatherData
import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.models.UserProfile
class SealevelPressureDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "sealevelPressure"){
override fun getValue(data: WeatherData): Double? {
override fun getValue(data: WeatherData, userProfile: UserProfile): Double? {
return data.sealevelPressure
}
}

View File

@ -3,9 +3,10 @@ package de.timklge.karooheadwind.datatypes
import android.content.Context
import de.timklge.karooheadwind.weatherprovider.WeatherData
import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.models.UserProfile
class SurfacePressureDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "surfacePressure"){
override fun getValue(data: WeatherData): Double? {
override fun getValue(data: WeatherData, userProfile: UserProfile): Double? {
return data.surfacePressure
}
}

View File

@ -25,6 +25,7 @@ import de.timklge.karooheadwind.streamDatatypeIsVisible
import de.timklge.karooheadwind.streamSettings
import de.timklge.karooheadwind.streamUserProfile
import de.timklge.karooheadwind.throttle
import de.timklge.karooheadwind.util.msInUserUnit
import de.timklge.karooheadwind.weatherprovider.WeatherData
import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.extension.DataTypeImpl
@ -133,11 +134,7 @@ class TailwindAndRideSpeedDataType(
val absoluteWindDirection = weatherData?.windDirection
val windSpeed = weatherData?.windSpeed
val gustSpeed = weatherData?.windGusts
val rideSpeed = if (isImperial){
rideSpeedInMs * 2.23694
} else {
rideSpeedInMs * 3.6
}
val rideSpeed = rideSpeedInMs
StreamData(headingResponse, absoluteWindDirection, windSpeed, settings, rideSpeed = rideSpeed, isImperial = isImperial, gustSpeed = gustSpeed, isVisible = isVisible)
}
@ -169,15 +166,21 @@ class TailwindAndRideSpeedDataType(
WindDirectionIndicatorSetting.WIND_DIRECTION -> streamData.absoluteWindDirection + 180
}
val text = streamData.rideSpeed?.let { String.format(Locale.current.platformLocale, "%.1f", it) } ?: ""
val rideSpeedInUserUnit = msInUserUnit(streamData.rideSpeed ?: 0.0, streamData.isImperial)
val text = String.format(Locale.current.platformLocale, "%.1f", rideSpeedInUserUnit)
val wideMode = config.gridSize.first == 60
val gustSpeedInUserUnit = msInUserUnit(streamData.gustSpeed ?: 0.0, streamData.isImperial)
val gustSpeedAddon = if (wideMode) {
"-${streamData.gustSpeed?.roundToInt() ?: 0}"
"-${gustSpeedInUserUnit.roundToInt()}"
} else {
""
}
val windSpeedUserUnit = msInUserUnit(windSpeed, streamData.isImperial)
val subtextWithSign = when (streamData.settings.windDirectionIndicatorTextSetting) {
WindDirectionIndicatorTextSetting.HEADWIND_SPEED -> {
val headwindSpeed = cos( (windDirection + 180) * Math.PI / 180.0) * windSpeed
@ -186,9 +189,12 @@ class TailwindAndRideSpeedDataType(
val sign = if (headwindSpeed < 0) "+" else {
if (headwindSpeed > 0) "-" else ""
}
"$sign${headwindSpeed.roundToInt().absoluteValue} ${windSpeed.roundToInt()}${gustSpeedAddon}"
val headwindSpeedUserUnit = msInUserUnit(headwindSpeed, streamData.isImperial)
"$sign${headwindSpeedUserUnit.roundToInt().absoluteValue} ${windSpeedUserUnit.roundToInt()}${gustSpeedAddon}"
}
WindDirectionIndicatorTextSetting.WIND_SPEED -> "${windSpeed.roundToInt()}${gustSpeedAddon}"
WindDirectionIndicatorTextSetting.WIND_SPEED -> "${windSpeedUserUnit.roundToInt()}${gustSpeedAddon}"
WindDirectionIndicatorTextSetting.NONE -> ""
}
@ -197,11 +203,7 @@ class TailwindAndRideSpeedDataType(
if (streamData.settings.windDirectionIndicatorSetting == WindDirectionIndicatorSetting.HEADWIND_DIRECTION) {
val headwindSpeed = cos( (windDirection + 180) * Math.PI / 180.0) * windSpeed
val windSpeedInKmh = if (streamData.isImperial == true){
headwindSpeed / 2.23694 * 3.6
} else {
headwindSpeed
}
val windSpeedInKmh = headwindSpeed * 3.6
dayColor = interpolateWindColor(windSpeedInKmh, false, context)
nightColor = interpolateWindColor(windSpeedInKmh, true, context)
}

View File

@ -21,6 +21,7 @@ import de.timklge.karooheadwind.streamDatatypeIsVisible
import de.timklge.karooheadwind.streamSettings
import de.timklge.karooheadwind.streamUserProfile
import de.timklge.karooheadwind.throttle
import de.timklge.karooheadwind.util.msInUserUnit
import de.timklge.karooheadwind.weatherprovider.WeatherData
import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.extension.DataTypeImpl
@ -120,13 +121,8 @@ class TailwindDataType(
val absoluteWindDirection = weatherData?.windDirection
val windSpeed = weatherData?.windSpeed
val gustSpeed = weatherData?.windGusts
val rideSpeed = if (isImperial){
rideSpeedInMs * 2.23694
} else {
rideSpeedInMs * 3.6
}
StreamData(headingResponse, absoluteWindDirection, windSpeed, settings, rideSpeed = rideSpeed, isImperial = isImperial, gustSpeed = gustSpeed, isVisible = isVisible)
StreamData(headingResponse, absoluteWindDirection, windSpeed, settings, rideSpeed = rideSpeedInMs, isImperial = isImperial, gustSpeed = gustSpeed, isVisible = isVisible)
}
}
@ -164,24 +160,26 @@ class TailwindDataType(
val sign = if (headwindSpeed < 0) "+" else {
if (headwindSpeed > 0) "-" else ""
}
"$sign${headwindSpeed.roundToInt().absoluteValue}"
val headwindSpeedUserUnit = msInUserUnit(headwindSpeed, streamData.isImperial)
"$sign${headwindSpeedUserUnit.roundToInt().absoluteValue}"
}
WindDirectionIndicatorTextSetting.WIND_SPEED -> windSpeed.roundToInt().toString()
WindDirectionIndicatorTextSetting.WIND_SPEED -> msInUserUnit(windSpeed, streamData.isImperial).roundToInt().toString()
WindDirectionIndicatorTextSetting.NONE -> ""
}
val subtext = "${windSpeed.roundToInt()}-${streamData.gustSpeed?.roundToInt()}"
val windSpeedUserUnit = msInUserUnit(windSpeed, streamData.isImperial)
val gustSpeedUserUnit = msInUserUnit(streamData.gustSpeed ?: 0.0, streamData.isImperial)
val subtext = "${windSpeedUserUnit.roundToInt()}-${gustSpeedUserUnit.roundToInt()}"
var dayColor = Color(ContextCompat.getColor(context, R.color.black))
var nightColor = Color(ContextCompat.getColor(context, R.color.white))
if (streamData.settings.windDirectionIndicatorSetting == WindDirectionIndicatorSetting.HEADWIND_DIRECTION) {
val headwindSpeed = cos( (windDirection + 180) * Math.PI / 180.0) * windSpeed
val windSpeedInKmh = if (streamData.isImperial){
headwindSpeed / 2.23694 * 3.6
} else {
headwindSpeed
}
val windSpeedInKmh = headwindSpeed * 3.6
dayColor = interpolateWindColor(windSpeedInKmh, false, context)
nightColor = interpolateWindColor(windSpeedInKmh, true, context)
}

View File

@ -3,9 +3,15 @@ package de.timklge.karooheadwind.datatypes
import android.content.Context
import de.timklge.karooheadwind.weatherprovider.WeatherData
import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.models.DataType
import io.hammerhead.karooext.models.UserProfile
class TemperatureDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "temperature"){
override fun getValue(data: WeatherData): Double {
override fun getValue(data: WeatherData, userProfile: UserProfile): Double {
return data.temperature
}
override fun getFormatDataType(): String? {
return DataType.Type.TEMPERATURE
}
}

View File

@ -24,6 +24,9 @@ import de.timklge.karooheadwind.streamDatatypeIsVisible
import de.timklge.karooheadwind.streamSettings
import de.timklge.karooheadwind.streamUserProfile
import de.timklge.karooheadwind.throttle
import de.timklge.karooheadwind.util.celciusInUserUnit
import de.timklge.karooheadwind.util.millimetersInUserUnit
import de.timklge.karooheadwind.util.msInUserUnit
import de.timklge.karooheadwind.weatherprovider.WeatherData
import de.timklge.karooheadwind.weatherprovider.WeatherInterpretation
import io.hammerhead.karooext.KarooSystemService
@ -85,7 +88,7 @@ class WeatherDataType(
emit(StreamData(
WeatherData(
Instant.now().epochSecond, 0.0,
20.0, 50.0, 3.0, 0.0, 1013.25, 980.0, 15.0, 30.0, 30.0,
20, 50.0, 3.0, 0.0, 1013.25, 980.0, 15.0, 30.0, 30.0,
WeatherInterpretation.getKnownWeatherCodes().random(), isForecast = false,
isNight = listOf(true, false).random()
), HeadwindSettings(), isVisible = true))
@ -147,11 +150,11 @@ class WeatherDataType(
baseBitmap,
current = interpretation,
windBearing = data.windDirection.roundToInt(),
windSpeed = data.windSpeed.roundToInt(),
windGusts = data.windGusts.roundToInt(),
precipitation = data.precipitation,
windSpeed = msInUserUnit(data.windSpeed, userProfile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL).roundToInt(),
windGusts = msInUserUnit(data.windGusts, userProfile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL).roundToInt(),
precipitation = millimetersInUserUnit(data.precipitation, userProfile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL),
precipitationProbability = null,
temperature = data.temperature.roundToInt(),
temperature = celciusInUserUnit(data.temperature, userProfile?.preferredUnit?.temperature == UserProfile.PreferredUnit.UnitType.IMPERIAL).roundToInt(),
temperatureUnit = if (userProfile?.preferredUnit?.temperature != UserProfile.PreferredUnit.UnitType.IMPERIAL) TemperatureUnit.CELSIUS else TemperatureUnit.FAHRENHEIT,
timeLabel = formattedTime,
rowAlignment = when (config.alignment){

View File

@ -26,6 +26,7 @@ import io.hammerhead.karooext.internal.ViewEmitter
import io.hammerhead.karooext.models.ShowCustomStreamState
import io.hammerhead.karooext.models.StreamState
import io.hammerhead.karooext.models.UpdateGraphicConfig
import io.hammerhead.karooext.models.UserProfile
import io.hammerhead.karooext.models.ViewConfig
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@ -51,7 +52,7 @@ class WindDirectionDataType(val karooSystem: KarooSystemService, context: Contex
)
}
override fun getValue(data: WeatherData): Double {
override fun getValue(data: WeatherData, userProfile: UserProfile): Double {
return data.windDirection
}

View File

@ -3,9 +3,10 @@ package de.timklge.karooheadwind.datatypes
import android.content.Context
import de.timklge.karooheadwind.weatherprovider.WeatherData
import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.models.UserProfile
class WindGustsDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "windGusts"){
override fun getValue(data: WeatherData): Double {
override fun getValue(data: WeatherData, userProfile: UserProfile): Double {
return data.windGusts
}
}

View File

@ -3,9 +3,10 @@ package de.timklge.karooheadwind.datatypes
import android.content.Context
import de.timklge.karooheadwind.weatherprovider.WeatherData
import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.models.UserProfile
class WindSpeedDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "windSpeed"){
override fun getValue(data: WeatherData): Double {
override fun getValue(data: WeatherData, userProfile: UserProfile): Double {
return data.windSpeed
}
}

View File

@ -37,6 +37,9 @@ import de.timklge.karooheadwind.streamCurrentWeatherData
import de.timklge.karooheadwind.streamStats
import de.timklge.karooheadwind.streamUpcomingRoute
import de.timklge.karooheadwind.streamUserProfile
import de.timklge.karooheadwind.util.celciusInUserUnit
import de.timklge.karooheadwind.util.millimetersInUserUnit
import de.timklge.karooheadwind.util.msInUserUnit
import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.models.UserProfile
import java.time.Instant
@ -110,10 +113,10 @@ fun WeatherScreen(onFinish: () -> Unit) {
baseBitmap = baseBitmap,
current = WeatherInterpretation.fromWeatherCode(currentWeatherData?.weatherCode),
windBearing = currentWeatherData?.windDirection?.roundToInt() ?: 0,
windSpeed = currentWeatherData?.windSpeed?.roundToInt() ?: 0,
windGusts = currentWeatherData?.windGusts?.roundToInt() ?: 0,
precipitation = currentWeatherData?.precipitation ?: 0.0,
temperature = currentWeatherData?.temperature?.toInt() ?: 0,
windSpeed = msInUserUnit(currentWeatherData?.windSpeed ?: 0.0, profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL).roundToInt(),
windGusts = msInUserUnit(currentWeatherData?.windGusts ?: 0.0, profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL).roundToInt(),
precipitation = millimetersInUserUnit(currentWeatherData?.precipitation ?: 0.0, profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL),
temperature = celciusInUserUnit(currentWeatherData?.temperature ?: 0.0, profile?.preferredUnit?.temperature == UserProfile.PreferredUnit.UnitType.IMPERIAL).roundToInt(),
temperatureUnit = if(profile?.preferredUnit?.temperature == UserProfile.PreferredUnit.UnitType.METRIC) TemperatureUnit.CELSIUS else TemperatureUnit.FAHRENHEIT,
timeLabel = formattedTime,
dateLabel = formattedDate,
@ -230,10 +233,10 @@ fun WeatherScreen(onFinish: () -> Unit) {
baseBitmap,
current = interpretation,
windBearing = weatherData?.windDirection?.roundToInt() ?: 0,
windSpeed = weatherData?.windSpeed?.roundToInt() ?: 0,
windGusts = weatherData?.windGusts?.roundToInt() ?: 0,
precipitation = weatherData?.precipitation ?: 0.0,
temperature = weatherData?.temperature?.toInt() ?: 0,
windSpeed = msInUserUnit(currentWeatherData?.windSpeed ?: 0.0, profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL).roundToInt(),
windGusts = msInUserUnit(currentWeatherData?.windGusts ?: 0.0, profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL).roundToInt(),
precipitation = millimetersInUserUnit(weatherData?.precipitation ?: 0.0, profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL),
temperature = celciusInUserUnit(weatherData?.temperature ?: 0.0, profile?.preferredUnit?.temperature == UserProfile.PreferredUnit.UnitType.IMPERIAL).roundToInt(),
temperatureUnit = if (profile?.preferredUnit?.temperature != UserProfile.PreferredUnit.UnitType.IMPERIAL) TemperatureUnit.CELSIUS else TemperatureUnit.FAHRENHEIT,
timeLabel = formattedForecastTime,
dateLabel = formattedForecastDate,

View File

@ -50,7 +50,7 @@ fun WeatherWidget(
isImperial: Boolean,
isNight: Boolean
) {
val fontSize = 20.sp
val fontSize = 18.sp
Row(
modifier = Modifier.fillMaxWidth().padding(5.dp),
@ -106,7 +106,6 @@ fun WeatherWidget(
)
Column(horizontalAlignment = Alignment.End) {
// Temperature (larger)
Row(
verticalAlignment = Alignment.CenterVertically
) {

View File

@ -0,0 +1,26 @@
package de.timklge.karooheadwind.util
fun celciusInUserUnit(celcius: Double, isImperial: Boolean): Double {
return if (isImperial) {
celcius * 9.0 / 5 + 32.0
} else {
celcius
}
}
fun millimetersInUserUnit(millimeters: Double, isImperial: Boolean): Double {
return if (isImperial) {
millimeters / 25.4
} else {
millimeters
}
}
// Returns the given speed value (m / s) in user unit (km/h or mph)
fun msInUserUnit(ms: Double, isImperial: Boolean): Double {
return if (isImperial) {
ms * 2.2369362920544
} else {
ms * 3.6
}
}

View File

@ -6,12 +6,12 @@ import kotlinx.serialization.Serializable
data class WeatherData(
val time: Long,
val temperature: Double,
val relativeHumidity: Double? = null,
val relativeHumidity: Int,
val precipitation: Double,
val precipitationProbability: Double? = null,
val cloudCover: Double? = null,
val sealevelPressure: Double? = null,
val surfacePressure: Double? = null,
val cloudCover: Double,
val sealevelPressure: Double,
val surfacePressure: Double,
val windSpeed: Double,
val windDirection: Double,
val windGusts: Double,

View File

@ -12,7 +12,7 @@ data class OpenMeteoWeatherData(
@SerialName("precipitation") val precipitation: Double,
@SerialName("cloud_cover") val cloudCover: Int,
@SerialName("surface_pressure") val surfacePressure: Double,
@SerialName("pressure_msl") val sealevelPressure: Double? = null,
@SerialName("pressure_msl") val sealevelPressure: Double,
@SerialName("wind_speed_10m") val windSpeed: Double,
@SerialName("wind_direction_10m") val windDirection: Double,
@SerialName("wind_gusts_10m") val windGusts: Double,
@ -21,7 +21,7 @@ data class OpenMeteoWeatherData(
) {
fun toWeatherData(): WeatherData = WeatherData(
temperature = temperature,
relativeHumidity = relativeHumidity.toDouble(),
relativeHumidity = relativeHumidity,
precipitation = precipitation,
cloudCover = cloudCover.toDouble(),
surfacePressure = surfacePressure,
@ -32,7 +32,7 @@ data class OpenMeteoWeatherData(
weatherCode = weatherCode,
time = time,
isForecast = false,
isNight = isDay == 0
isNight = isDay == 0,
)
}

View File

@ -14,7 +14,11 @@ data class OpenMeteoWeatherForecastData(
@SerialName("wind_speed_10m") val windSpeed: List<Double>,
@SerialName("wind_direction_10m") val windDirection: List<Double>,
@SerialName("wind_gusts_10m") val windGusts: List<Double>,
@SerialName("cloud_cover") val cloudCover: List<Double>,
@SerialName("surface_pressure") val surfacePressure: List<Double>,
@SerialName("pressure_msl") val sealevelPressure: List<Double>,
@SerialName("is_day") val isDay: List<Int>,
@SerialName("relative_humidity_2m") val relativeHumidity: List<Int>,
) {
fun toWeatherData(): List<WeatherData> {
return time.mapIndexed { index, t ->
@ -29,6 +33,10 @@ data class OpenMeteoWeatherForecastData(
isNight = isDay[index] == 0,
time = t,
isForecast = true,
cloudCover = cloudCover[index],
surfacePressure = surfacePressure[index],
sealevelPressure = sealevelPressure[index],
relativeHumidity = relativeHumidity[index],
)
}
}

View File

@ -3,10 +3,7 @@ package de.timklge.karooheadwind.weatherprovider.openmeteo
import android.util.Log
import de.timklge.karooheadwind.HeadwindSettings
import de.timklge.karooheadwind.KarooHeadwindExtension
import de.timklge.karooheadwind.PrecipitationUnit
import de.timklge.karooheadwind.TemperatureUnit
import de.timklge.karooheadwind.WeatherDataProvider
import de.timklge.karooheadwind.WindUnit
import de.timklge.karooheadwind.datatypes.GpsCoordinates
import de.timklge.karooheadwind.jsonWithUnknownKeys
import de.timklge.karooheadwind.weatherprovider.WeatherDataResponse
@ -28,16 +25,12 @@ import kotlin.time.Duration.Companion.seconds
class OpenMeteoWeatherProvider : WeatherProvider {
@OptIn(FlowPreview::class)
private suspend fun makeOpenMeteoWeatherRequest(karooSystemService: KarooSystemService, gpsCoordinates: List<GpsCoordinates>, settings: HeadwindSettings, profile: UserProfile?): HttpResponseState.Complete {
val precipitationUnit = if (profile?.preferredUnit?.distance != UserProfile.PreferredUnit.UnitType.IMPERIAL) PrecipitationUnit.MILLIMETERS else PrecipitationUnit.INCH
val temperatureUnit = if (profile?.preferredUnit?.temperature != UserProfile.PreferredUnit.UnitType.IMPERIAL) TemperatureUnit.CELSIUS else TemperatureUnit.FAHRENHEIT
val windUnit = if (profile?.preferredUnit?.distance != UserProfile.PreferredUnit.UnitType.IMPERIAL) WindUnit.KILOMETERS_PER_HOUR else WindUnit.MILES_PER_HOUR
private suspend fun makeOpenMeteoWeatherRequest(karooSystemService: KarooSystemService, gpsCoordinates: List<GpsCoordinates>): HttpResponseState.Complete {
val response = callbackFlow {
// https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41&current=is_day,surface_pressure,pressure_msl,temperature_2m,relative_humidity_2m,precipitation,weather_code,cloud_cover,wind_speed_10m,wind_direction_10m,wind_gusts_10m&hourly=temperature_2m,precipitation_probability,precipitation,weather_code,wind_speed_10m,wind_direction_10m,wind_gusts_10m&timeformat=unixtime&past_hours=1&forecast_days=1&forecast_hours=12
val lats = gpsCoordinates.joinToString(",") { String.format(Locale.US, "%.6f", it.lat) }
val lons = gpsCoordinates.joinToString(",") { String.format(Locale.US, "%.6f", it.lon) }
val url = "https://api.open-meteo.com/v1/forecast?latitude=${lats}&longitude=${lons}&current=is_day,surface_pressure,pressure_msl,temperature_2m,relative_humidity_2m,precipitation,weather_code,cloud_cover,wind_speed_10m,wind_direction_10m,wind_gusts_10m&hourly=temperature_2m,precipitation_probability,precipitation,weather_code,wind_speed_10m,wind_direction_10m,wind_gusts_10m,is_day&timeformat=unixtime&past_hours=0&forecast_days=1&forecast_hours=12&wind_speed_unit=${windUnit.id}&precipitation_unit=${precipitationUnit.id}&temperature_unit=${temperatureUnit.id}"
val url = "https://api.open-meteo.com/v1/forecast?latitude=${lats}&longitude=${lons}&current=is_day,surface_pressure,pressure_msl,temperature_2m,relative_humidity_2m,precipitation,weather_code,cloud_cover,wind_speed_10m,wind_direction_10m,wind_gusts_10m&hourly=temperature_2m,precipitation_probability,precipitation,weather_code,wind_speed_10m,wind_direction_10m,wind_gusts_10m,is_day,surface_pressure,pressure_msl,relative_humidity_2m,cloud_cover&timeformat=unixtime&past_hours=0&forecast_days=1&forecast_hours=12&wind_speed_unit=ms"
Log.d(KarooHeadwindExtension.TAG, "Http request to ${url}...")
@ -84,7 +77,7 @@ class OpenMeteoWeatherProvider : WeatherProvider {
settings: HeadwindSettings,
profile: UserProfile?
): WeatherDataResponse {
val openMeteoResponse = makeOpenMeteoWeatherRequest(karooSystem, coordinates, settings, profile)
val openMeteoResponse = makeOpenMeteoWeatherRequest(karooSystem, coordinates)
val responseBody = openMeteoResponse.body?.let { String(it) } ?: throw WeatherProviderException(500, "Null response from OpenMeteo")
val weatherData = if (coordinates.size == 1) {

View File

@ -33,7 +33,7 @@ data class OpenWeatherMapForecastData(
return WeatherData(
temperature = temp,
relativeHumidity = humidity.toDouble(),
relativeHumidity = humidity,
precipitation = rain?.h1 ?: 0.0,
cloudCover = clouds.toDouble(),
surfacePressure = pressure.toDouble(),

View File

@ -23,7 +23,7 @@ data class OpenWeatherMapWeatherData(
fun toWeatherData(): WeatherData = WeatherData(
temperature = temp,
relativeHumidity = humidity.toDouble(),
relativeHumidity = humidity,
precipitation = rain?.h1 ?: 0.0,
cloudCover = clouds.toDouble(),
surfacePressure = pressure.toDouble(),

View File

@ -69,7 +69,7 @@ class OpenWeatherMapWeatherProvider(private val apiKey: String) : WeatherProvide
profile: UserProfile?
): WeatherDataResponse {
val response = makeOpenWeatherMapRequest(karooSystem, coordinates, apiKey, profile)
val response = makeOpenWeatherMapRequest(karooSystem, coordinates, apiKey)
val responseBody = response.body?.let { String(it) } ?: throw Exception("Null response from OpenWeatherMap")
val responses = mutableListOf<WeatherDataForLocation>()
@ -89,21 +89,15 @@ class OpenWeatherMapWeatherProvider(private val apiKey: String) : WeatherProvide
private suspend fun makeOpenWeatherMapRequest(
service: KarooSystemService,
coordinates: List<GpsCoordinates>,
apiKey: String,
profile: UserProfile?
apiKey: String
): HttpResponseState.Complete {
val response = callbackFlow {
// OpenWeatherMap only supports setting imperial or metric units for all measurements, not individually for distance / temperature
val unitsString = if (profile?.preferredUnit?.temperature == UserProfile.PreferredUnit.UnitType.IMPERIAL || profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL) {
"imperial"
} else {
"metric"
}
val coordinate = coordinates.first()
// URL API 3.0 with onecall endpoint
val url = "https://api.openweathermap.org/data/3.0/onecall?lat=${coordinate.lat}&lon=${coordinate.lon}" +
"&appid=$apiKey&exclude=minutely,daily,alerts&units=${unitsString}"
"&appid=$apiKey&exclude=minutely,daily,alerts&units=metric"
Log.d(KarooHeadwindExtension.TAG, "Http request to OpenWeatherMap API 3.0: $url")