Add UV Index to current weather and forecast (#159)

This commit is contained in:
Julien B. 2025-07-07 17:41:55 +02:00 committed by GitHub
parent be7ca192b2
commit 5169048143
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 69 additions and 26 deletions

View File

@ -294,9 +294,9 @@ fun lerpWeather(
weatherCode = closestWeatherData.weatherCode,
isForecast = closestWeatherData.isForecast,
isNight = closestWeatherData.isNight,
uvi = start.uvi + (end.uvi - start.uvi) * factor
)
}
fun lerpWeatherTime(
weatherData: List<WeatherData>?,
currentWeatherData: WeatherData

View File

@ -17,6 +17,7 @@ import de.timklge.karooheadwind.datatypes.SealevelPressureDataType
import de.timklge.karooheadwind.datatypes.SurfacePressureDataType
import de.timklge.karooheadwind.datatypes.TailwindAndRideSpeedDataType
import de.timklge.karooheadwind.datatypes.TemperatureDataType
import de.timklge.karooheadwind.datatypes.UviDataType
import de.timklge.karooheadwind.datatypes.TemperatureForecastDataType
import de.timklge.karooheadwind.datatypes.WeatherForecastDataType
import de.timklge.karooheadwind.datatypes.WindDirectionAndSpeedDataType
@ -83,7 +84,8 @@ class KarooHeadwindExtension : KarooExtension("karoo-headwind", BuildConfig.VERS
WindDirectionAndSpeedDataType(karooSystem, applicationContext),
RelativeGradeDataType(karooSystem, applicationContext),
RelativeElevationGainDataType(karooSystem, applicationContext),
TemperatureDataType(karooSystem, applicationContext)
TemperatureDataType(karooSystem, applicationContext),
UviDataType(karooSystem, applicationContext)
)
}

View File

@ -65,14 +65,14 @@ import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch
import java.time.Instant
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoUnit
import kotlin.math.abs
import kotlin.math.roundToInt
abstract class ForecastDataType(private val karooSystem: KarooSystemService, typeId: String) : DataTypeImpl("karoo-headwind", typeId) {
@Composable
abstract fun RenderWidget(arrowBitmap: Bitmap,
abstract fun RenderWidget(
arrowBitmap: Bitmap,
current: WeatherInterpretation,
windBearing: Int,
windSpeed: Int,
@ -85,7 +85,9 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
dateLabel: String?,
distance: Double?,
isImperial: Boolean,
isNight: Boolean)
isNight: Boolean,
uvi: Double
)
@OptIn(ExperimentalGlanceRemoteViewsApi::class)
private val glance = GlanceRemoteViews()
@ -107,6 +109,7 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
val weatherData = (0..<12).map {
val forecastTime = timeAtFullHour + it * 60 * 60
val forecastTemperature = 20.0 + (-20..20).random()
val forecastUvi = 0.0 + (0..12).random().toDouble()
val forecastPrecipitation = 0.0 + (0..10).random()
val forecastPrecipitationProbability = (0..100).random()
val forecastWeatherCode = WeatherInterpretation.getKnownWeatherCodes().random()
@ -127,7 +130,8 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
windGusts = forecastWindGusts,
weatherCode = forecastWeatherCode,
isForecast = true,
isNight = it < 2
isNight = it < 2,
uvi = forecastUvi
)
}
@ -149,7 +153,8 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
windGusts = 10.0,
weatherCode = WeatherInterpretation.getKnownWeatherCodes().random(),
isForecast = false,
isNight = false
isNight = false,
uvi = 2.0
),
coords = GpsCoordinates(0.0, 0.0, distanceAlongRoute = index * distancePerHour),
timezone = "UTC",
@ -333,7 +338,8 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
dateLabel = if (hasNewDate) formattedDate else null,
distance = null,
isImperial = settingsAndProfile.isImperial,
isNight = data.current.isNight
isNight = data.current.isNight,
uvi = data.current.uvi
)
previousDate = formattedDate
@ -359,7 +365,8 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
dateLabel = if (hasNewDate) formattedDate else null,
distance = if (settingsAndProfile.settings.showDistanceInForecast) distanceFromCurrent else null,
isImperial = settingsAndProfile.isImperial,
isNight = weatherData?.isNight == true
isNight = weatherData?.isNight == true,
uvi = weatherData?.uvi ?: 0.0
)
previousDate = formattedDate

View File

@ -94,6 +94,7 @@ abstract class LineGraphForecastDataType(private val karooSystem: KarooSystemSer
val forecastWindSpeed = 0.0 + (0..10).random()
val forecastWindDirection = 0.0 + (0..360).random()
val forecastWindGusts = 0.0 + (0..10).random()
val forcastUvi = 0.0 + (0..12).random()
WeatherData(
time = forecastTime,
temperature = forecastTemperature,
@ -108,7 +109,8 @@ abstract class LineGraphForecastDataType(private val karooSystem: KarooSystemSer
windGusts = forecastWindGusts,
weatherCode = forecastWeatherCode,
isForecast = true,
isNight = it < 2
isNight = it < 2,
uvi = forcastUvi
)
}
@ -130,7 +132,8 @@ abstract class LineGraphForecastDataType(private val karooSystem: KarooSystemSer
windGusts = 10.0,
weatherCode = WeatherInterpretation.getKnownWeatherCodes().random(),
isForecast = false,
isNight = false
isNight = false,
uvi = 2.0
),
coords = GpsCoordinates(0.0, 0.0, distanceAlongRoute = index * distancePerHour),
timezone = "UTC",

View File

@ -0,0 +1,12 @@
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 UviDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "uvi"){
override fun getValue(data: WeatherData, userProfile: UserProfile): Double {
return data.uvi
}
}

View File

@ -23,6 +23,7 @@ class WeatherForecastDataType(karooSystem: KarooSystemService) : ForecastDataTyp
distance: Double?,
isImperial: Boolean,
isNight: Boolean,
uvi: Double,
) {
Weather(
arrowBitmap = arrowBitmap,

View File

@ -17,6 +17,7 @@ data class WeatherData(
val windGusts: Double,
val weatherCode: Int,
val isForecast: Boolean,
val isNight: Boolean
val isNight: Boolean,
val uvi: Double,
)

View File

@ -18,6 +18,7 @@ data class OpenMeteoWeatherData(
@SerialName("wind_gusts_10m") val windGusts: Double,
@SerialName("weather_code") val weatherCode: Int,
@SerialName("is_day") val isDay: Int,
@SerialName("uv_index") val uvi: Double,
) {
fun toWeatherData(): WeatherData = WeatherData(
temperature = temperature,
@ -33,6 +34,7 @@ data class OpenMeteoWeatherData(
time = time,
isForecast = false,
isNight = isDay == 0,
uvi = uvi
)
}

View File

@ -19,6 +19,7 @@ data class OpenMeteoWeatherForecastData(
@SerialName("pressure_msl") val sealevelPressure: List<Double>,
@SerialName("is_day") val isDay: List<Int>,
@SerialName("relative_humidity_2m") val relativeHumidity: List<Int>,
@SerialName("uv_index") val uvi: List<Double>,
) {
fun toWeatherData(): List<WeatherData> {
return time.mapIndexed { index, t ->
@ -37,6 +38,7 @@ data class OpenMeteoWeatherForecastData(
surfacePressure = surfacePressure[index],
sealevelPressure = sealevelPressure[index],
relativeHumidity = relativeHumidity[index],
uvi = uvi[index]
)
}
}

View File

@ -30,7 +30,7 @@ class OpenMeteoWeatherProvider : WeatherProvider {
// 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,surface_pressure,pressure_msl,relative_humidity_2m,cloud_cover&timeformat=unixtime&past_hours=0&forecast_days=1&forecast_hours=12&wind_speed_unit=ms"
val url = "https://api.open-meteo.com/v1/forecast?latitude=${lats}&longitude=${lons}&current=is_day,surface_pressure,pressure_msl,uv_index,temperature_2m,relative_humidity_2m,precipitation,weather_code,cloud_cover,wind_speed_10m,wind_direction_10m,wind_gusts_10m&hourly=uv_index,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}...")

View File

@ -20,7 +20,8 @@ data class OpenWeatherMapForecastData(
val pop: Double,
val rain: Rain? = null,
val snow: Snow? = null,
val weather: List<Weather>
val weather: List<Weather>,
val uvi: Double,
) {
fun toWeatherData(currentWeatherData: OpenWeatherMapWeatherData): WeatherData {
val dtInstant = Instant.ofEpochSecond(dt)
@ -32,6 +33,7 @@ data class OpenWeatherMapForecastData(
val sunsetTime = sunsetInstant.atZone(ZoneOffset.UTC).toLocalTime()
return WeatherData(
uvi = uvi,
temperature = temp,
relativeHumidity = humidity,
precipitation = rain?.h1 ?: 0.0,

View File

@ -19,9 +19,11 @@ data class OpenWeatherMapWeatherData(
val wind_gust: Double? = null,
val rain: Rain? = null,
val snow: Snow? = null,
val uvi: Double,
val weather: List<Weather>){
fun toWeatherData(): WeatherData = WeatherData(
uvi = uvi,
temperature = temp,
relativeHumidity = humidity,
precipitation = rain?.h1 ?: 0.0,

View File

@ -22,6 +22,8 @@
<string name="sealevelPressure">Sealevel pressure</string>
<string name="sealevelPressure_description">Atmospheric pressure at sea level in configured unit</string>
<string name="weather_forecast">Weather Forecast</string>
<string name="uvi">UV Index</string>
<string name="uvi_description">Current UV Index at current location</string>
<string name="weather_forecast_description">Current hourly weather forecast</string>
<string name="temperature_forecast">Temperature Forecast</string>
<string name="temperature_forecast_description">Current hourly temperature forecast</string>

View File

@ -131,6 +131,13 @@
icon="@drawable/thermometer"
typeId="temperature" />
<DataType
description="@string/uvi_description"
displayName="@string/uvi"
graphical="false"
icon="@drawable/thermometer"
typeId="uvi" />
<DataType
description="@string/relativeGrade_description"
displayName="@string/relativeGrade"