Add moon icon to represent clear sky at night (#123)

This commit is contained in:
timklge 2025-05-05 21:26:55 +02:00 committed by GitHub
parent cff4b07d7d
commit 96bee1b55c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 113 additions and 64 deletions

View File

@ -276,7 +276,8 @@ fun lerpWeather(
windDirection = lerpAngle(start.windDirection, end.windDirection, factor), windDirection = lerpAngle(start.windDirection, end.windDirection, factor),
windGusts = start.windGusts + (end.windGusts - start.windGusts) * factor, windGusts = start.windGusts + (end.windGusts - start.windGusts) * factor,
weatherCode = closestWeatherData.weatherCode, weatherCode = closestWeatherData.weatherCode,
isForecast = closestWeatherData.isForecast isForecast = closestWeatherData.isForecast,
isNight = closestWeatherData.isNight,
) )
} }

View File

@ -50,7 +50,6 @@ data class HeadwindWidgetSettings(
} }
} }
//Moded with openweahtermap.org
@Serializable @Serializable
data class HeadwindStats( data class HeadwindStats(
val lastSuccessfulWeatherRequest: Long? = null, val lastSuccessfulWeatherRequest: Long? = null,

View File

@ -28,11 +28,7 @@ import de.timklge.karooheadwind.KarooHeadwindExtension
import de.timklge.karooheadwind.R import de.timklge.karooheadwind.R
import de.timklge.karooheadwind.TemperatureUnit import de.timklge.karooheadwind.TemperatureUnit
import de.timklge.karooheadwind.UpcomingRoute import de.timklge.karooheadwind.UpcomingRoute
import de.timklge.karooheadwind.weatherprovider.WeatherData
import de.timklge.karooheadwind.weatherprovider.WeatherDataForLocation
import de.timklge.karooheadwind.WeatherDataProvider import de.timklge.karooheadwind.WeatherDataProvider
import de.timklge.karooheadwind.weatherprovider.WeatherDataResponse
import de.timklge.karooheadwind.weatherprovider.WeatherInterpretation
import de.timklge.karooheadwind.getHeadingFlow import de.timklge.karooheadwind.getHeadingFlow
import de.timklge.karooheadwind.streamCurrentForecastWeatherData import de.timklge.karooheadwind.streamCurrentForecastWeatherData
import de.timklge.karooheadwind.streamSettings import de.timklge.karooheadwind.streamSettings
@ -40,6 +36,10 @@ import de.timklge.karooheadwind.streamUpcomingRoute
import de.timklge.karooheadwind.streamUserProfile import de.timklge.karooheadwind.streamUserProfile
import de.timklge.karooheadwind.streamWidgetSettings import de.timklge.karooheadwind.streamWidgetSettings
import de.timklge.karooheadwind.throttle import de.timklge.karooheadwind.throttle
import de.timklge.karooheadwind.weatherprovider.WeatherData
import de.timklge.karooheadwind.weatherprovider.WeatherDataForLocation
import de.timklge.karooheadwind.weatherprovider.WeatherDataResponse
import de.timklge.karooheadwind.weatherprovider.WeatherInterpretation
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.ViewEmitter import io.hammerhead.karooext.internal.ViewEmitter
@ -78,7 +78,8 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
timeLabel: String, timeLabel: String,
dateLabel: String?, dateLabel: String?,
distance: Double?, distance: Double?,
isImperial: Boolean) isImperial: Boolean,
isNight: Boolean)
@OptIn(ExperimentalGlanceRemoteViewsApi::class) @OptIn(ExperimentalGlanceRemoteViewsApi::class)
private val glance = GlanceRemoteViews() private val glance = GlanceRemoteViews()
@ -123,7 +124,8 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
windDirection = forecastWindDirection, windDirection = forecastWindDirection,
windGusts = forecastWindGusts, windGusts = forecastWindGusts,
weatherCode = forecastWeatherCode, weatherCode = forecastWeatherCode,
isForecast = true isForecast = true,
isNight = it < 2
) )
} }
@ -144,7 +146,8 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
windDirection = 180.0, windDirection = 180.0,
windGusts = 10.0, windGusts = 10.0,
weatherCode = WeatherInterpretation.getKnownWeatherCodes().random(), weatherCode = WeatherInterpretation.getKnownWeatherCodes().random(),
isForecast = false isForecast = false,
isNight = false
), ),
coords = GpsCoordinates(0.0, 0.0, distanceAlongRoute = index * distancePerHour), coords = GpsCoordinates(0.0, 0.0, distanceAlongRoute = index * distancePerHour),
timezone = "UTC", timezone = "UTC",
@ -305,7 +308,8 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
timeLabel = formattedTime, timeLabel = formattedTime,
dateLabel = if (hasNewDate) formattedDate else null, dateLabel = if (hasNewDate) formattedDate else null,
distance = null, distance = null,
isImperial = settingsAndProfile.isImperial isImperial = settingsAndProfile.isImperial,
isNight = data.current.isNight
) )
previousDate = formattedDate previousDate = formattedDate
@ -330,7 +334,8 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
timeLabel = formattedTime, timeLabel = formattedTime,
dateLabel = if (hasNewDate) formattedDate else null, dateLabel = if (hasNewDate) formattedDate else null,
distance = if (settingsAndProfile.settings.showDistanceInForecast) distanceFromCurrent else null, distance = if (settingsAndProfile.settings.showDistanceInForecast) distanceFromCurrent else null,
isImperial = settingsAndProfile.isImperial isImperial = settingsAndProfile.isImperial,
isNight = weatherData?.isNight == true
) )
previousDate = formattedDate previousDate = formattedDate

View File

@ -34,13 +34,14 @@ fun GraphicalForecast(
distance: Double? = null, distance: Double? = null,
timeLabel: String? = null, timeLabel: String? = null,
rowAlignment: Alignment.Horizontal = Alignment.Horizontal.CenterHorizontally, rowAlignment: Alignment.Horizontal = Alignment.Horizontal.CenterHorizontally,
isImperial: Boolean? isImperial: Boolean?,
isNight: Boolean,
) { ) {
Column(modifier = GlanceModifier.fillMaxHeight().padding(1.dp).width(86.dp), horizontalAlignment = rowAlignment) { Column(modifier = GlanceModifier.fillMaxHeight().padding(1.dp).width(86.dp), horizontalAlignment = rowAlignment) {
Row(modifier = GlanceModifier.defaultWeight().wrapContentWidth(), horizontalAlignment = rowAlignment, verticalAlignment = Alignment.CenterVertically) { Row(modifier = GlanceModifier.defaultWeight().wrapContentWidth(), horizontalAlignment = rowAlignment, verticalAlignment = Alignment.CenterVertically) {
Image( Image(
modifier = GlanceModifier.defaultWeight().wrapContentWidth().padding(1.dp), modifier = GlanceModifier.defaultWeight().wrapContentWidth().padding(1.dp),
provider = ImageProvider(getWeatherIcon(current)), provider = ImageProvider(getWeatherIcon(current, isNight)),
contentDescription = "Current weather information", contentDescription = "Current weather information",
contentScale = ContentScale.Fit, contentScale = ContentScale.Fit,
colorFilter = ColorFilter.tint(ColorProvider(Color.Black, Color.White)) colorFilter = ColorFilter.tint(ColorProvider(Color.Black, Color.White))
@ -96,13 +97,15 @@ class GraphicalForecastDataType(karooSystem: KarooSystemService) : ForecastDataT
timeLabel: String, timeLabel: String,
dateLabel: String?, dateLabel: String?,
distance: Double?, distance: Double?,
isImperial: Boolean isImperial: Boolean,
isNight: Boolean,
) { ) {
GraphicalForecast( GraphicalForecast(
current = current, current = current,
distance = distance, distance = distance,
timeLabel = timeLabel, timeLabel = timeLabel,
isImperial = isImperial isImperial = isImperial,
isNight = isNight
) )
} }
} }

View File

@ -25,7 +25,6 @@ import de.timklge.karooheadwind.weatherprovider.WeatherInterpretation
import io.hammerhead.karooext.KarooSystemService import io.hammerhead.karooext.KarooSystemService
import kotlin.math.absoluteValue import kotlin.math.absoluteValue
import kotlin.math.ceil import kotlin.math.ceil
import kotlin.math.roundToInt
@Composable @Composable
fun PrecipitationForecast( fun PrecipitationForecast(
@ -34,7 +33,7 @@ fun PrecipitationForecast(
distance: Double? = null, distance: Double? = null,
timeLabel: String? = null, timeLabel: String? = null,
rowAlignment: Alignment.Horizontal = Alignment.Horizontal.CenterHorizontally, rowAlignment: Alignment.Horizontal = Alignment.Horizontal.CenterHorizontally,
isImperial: Boolean? isImperial: Boolean?,
) { ) {
Column(modifier = GlanceModifier.fillMaxHeight().padding(1.dp).width(86.dp), horizontalAlignment = rowAlignment) { Column(modifier = GlanceModifier.fillMaxHeight().padding(1.dp).width(86.dp), horizontalAlignment = rowAlignment) {
Row(modifier = GlanceModifier.defaultWeight().fillMaxWidth(), horizontalAlignment = rowAlignment, verticalAlignment = Alignment.CenterVertically) { Row(modifier = GlanceModifier.defaultWeight().fillMaxWidth(), horizontalAlignment = rowAlignment, verticalAlignment = Alignment.CenterVertically) {
@ -95,14 +94,15 @@ class PrecipitationForecastDataType(karooSystem: KarooSystemService) : ForecastD
timeLabel: String, timeLabel: String,
dateLabel: String?, dateLabel: String?,
distance: Double?, distance: Double?,
isImperial: Boolean isImperial: Boolean,
isNight: Boolean,
) { ) {
PrecipitationForecast( PrecipitationForecast(
precipitation = ceil(precipitation).toInt(), precipitation = ceil(precipitation).toInt(),
precipitationProbability = precipitationProbability, precipitationProbability = precipitationProbability,
distance = distance, distance = distance,
timeLabel = timeLabel, timeLabel = timeLabel,
isImperial = isImperial isImperial = isImperial,
) )
} }
} }

View File

@ -91,14 +91,15 @@ class TemperatureForecastDataType(karooSystem: KarooSystemService) : ForecastDat
timeLabel: String, timeLabel: String,
dateLabel: String?, dateLabel: String?,
distance: Double?, distance: Double?,
isImperial: Boolean isImperial: Boolean,
isNight: Boolean
) { ) {
TemperatureForecast( TemperatureForecast(
temperature = temperature, temperature = temperature,
temperatureUnit = temperatureUnit, temperatureUnit = temperatureUnit,
distance = distance, distance = distance,
timeLabel = timeLabel, timeLabel = timeLabel,
isImperial = isImperial isImperial = isImperial,
) )
} }
} }

View File

@ -16,6 +16,7 @@ import de.timklge.karooheadwind.HeadingResponse
import de.timklge.karooheadwind.HeadwindSettings import de.timklge.karooheadwind.HeadwindSettings
import de.timklge.karooheadwind.KarooHeadwindExtension import de.timklge.karooheadwind.KarooHeadwindExtension
import de.timklge.karooheadwind.MainActivity import de.timklge.karooheadwind.MainActivity
import de.timklge.karooheadwind.R
import de.timklge.karooheadwind.TemperatureUnit import de.timklge.karooheadwind.TemperatureUnit
import de.timklge.karooheadwind.getHeadingFlow import de.timklge.karooheadwind.getHeadingFlow
import de.timklge.karooheadwind.streamCurrentWeatherData import de.timklge.karooheadwind.streamCurrentWeatherData
@ -79,9 +80,12 @@ class WeatherDataType(
private fun previewFlow(): Flow<StreamData> = flow { private fun previewFlow(): Flow<StreamData> = flow {
while (true){ while (true){
emit(StreamData( emit(StreamData(
WeatherData(Instant.now().epochSecond, 0.0, 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.0, 50.0, 3.0, 0.0, 1013.25, 980.0, 15.0, 30.0, 30.0,
WeatherInterpretation.getKnownWeatherCodes().random(), isForecast = false), HeadwindSettings())) WeatherInterpretation.getKnownWeatherCodes().random(), isForecast = false,
isNight = listOf(true, false).random()
), HeadwindSettings()))
delay(5_000) delay(5_000)
} }
@ -96,7 +100,7 @@ class WeatherDataType(
val baseBitmap = BitmapFactory.decodeResource( val baseBitmap = BitmapFactory.decodeResource(
context.resources, context.resources,
de.timklge.karooheadwind.R.drawable.arrow_0 R.drawable.arrow_0
) )
val dataFlow = if (config.preview){ val dataFlow = if (config.preview){
@ -148,7 +152,8 @@ class WeatherDataType(
}, },
dateLabel = formattedDate, dateLabel = formattedDate,
singleDisplay = true, singleDisplay = true,
isImperial = userProfile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL isImperial = userProfile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL,
isNight = data.isNight,
) )
} }
} }

View File

@ -21,7 +21,8 @@ class WeatherForecastDataType(karooSystem: KarooSystemService) : ForecastDataTyp
timeLabel: String, timeLabel: String,
dateLabel: String?, dateLabel: String?,
distance: Double?, distance: Double?,
isImperial: Boolean isImperial: Boolean,
isNight: Boolean,
) { ) {
Weather( Weather(
arrowBitmap = arrowBitmap, arrowBitmap = arrowBitmap,
@ -36,7 +37,8 @@ class WeatherForecastDataType(karooSystem: KarooSystemService) : ForecastDataTyp
timeLabel = timeLabel, timeLabel = timeLabel,
dateLabel = dateLabel, dateLabel = dateLabel,
distance = distance, distance = distance,
isImperial = isImperial isImperial = isImperial,
isNight = isNight,
) )
} }

View File

@ -45,9 +45,9 @@ fun getShortDateFormatter(): DateTimeFormatter = DateTimeFormatter.ofPattern(
} }
).withZone(ZoneId.systemDefault()) ).withZone(ZoneId.systemDefault())
fun getWeatherIcon(interpretation: WeatherInterpretation): Int { fun getWeatherIcon(interpretation: WeatherInterpretation, isNight: Boolean): Int {
return when (interpretation){ return when (interpretation){
WeatherInterpretation.CLEAR -> R.drawable.bx_clear WeatherInterpretation.CLEAR -> if (isNight) R.drawable.moon else R.drawable.bx_clear
WeatherInterpretation.CLOUDY -> R.drawable.bx_cloud WeatherInterpretation.CLOUDY -> R.drawable.bx_cloud
WeatherInterpretation.RAINY -> R.drawable.bx_cloud_rain WeatherInterpretation.RAINY -> R.drawable.bx_cloud_rain
WeatherInterpretation.SNOWY -> R.drawable.bx_cloud_snow WeatherInterpretation.SNOWY -> R.drawable.bx_cloud_snow
@ -74,7 +74,8 @@ fun Weather(
rowAlignment: Alignment.Horizontal = Alignment.Horizontal.CenterHorizontally, rowAlignment: Alignment.Horizontal = Alignment.Horizontal.CenterHorizontally,
dateLabel: String? = null, dateLabel: String? = null,
singleDisplay: Boolean = false, singleDisplay: Boolean = false,
isImperial: Boolean? isImperial: Boolean?,
isNight: Boolean
) { ) {
val fontSize = if (singleDisplay) 19f else 14f val fontSize = if (singleDisplay) 19f else 14f
@ -83,7 +84,7 @@ fun Weather(
Row(modifier = GlanceModifier.defaultWeight().wrapContentWidth(), horizontalAlignment = rowAlignment, verticalAlignment = Alignment.CenterVertically) { Row(modifier = GlanceModifier.defaultWeight().wrapContentWidth(), horizontalAlignment = rowAlignment, verticalAlignment = Alignment.CenterVertically) {
Image( Image(
modifier = GlanceModifier.defaultWeight().wrapContentWidth().padding(1.dp), modifier = GlanceModifier.defaultWeight().wrapContentWidth().padding(1.dp),
provider = ImageProvider(getWeatherIcon(current)), provider = ImageProvider(getWeatherIcon(current, isNight)),
contentDescription = "Current weather information", contentDescription = "Current weather information",
contentScale = ContentScale.Fit, contentScale = ContentScale.Fit,
colorFilter = ColorFilter.tint(ColorProvider(Color.Black, Color.White)) colorFilter = ColorFilter.tint(ColorProvider(Color.Black, Color.White))

View File

@ -103,7 +103,8 @@ class WindForecastDataType(karooSystem: KarooSystemService) : ForecastDataType(k
timeLabel: String, timeLabel: String,
dateLabel: String?, dateLabel: String?,
distance: Double?, distance: Double?,
isImperial: Boolean isImperial: Boolean,
isNight: Boolean
) { ) {
WindForecast( WindForecast(
arrowBitmap = arrowBitmap, arrowBitmap = arrowBitmap,
@ -112,7 +113,7 @@ class WindForecastDataType(karooSystem: KarooSystemService) : ForecastDataType(k
gustSpeed = windGusts, gustSpeed = windGusts,
distance = distance, distance = distance,
timeLabel = timeLabel, timeLabel = timeLabel,
isImperial = isImperial isImperial = isImperial,
) )
} }
} }

View File

@ -120,6 +120,7 @@ fun WeatherScreen(onFinish: () -> Unit) {
distance = requestedWeatherPosition?.let { l -> location?.distanceTo(l)?.times(1000) }, distance = requestedWeatherPosition?.let { l -> location?.distanceTo(l)?.times(1000) },
includeDistanceLabel = false, includeDistanceLabel = false,
isImperial = profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL, isImperial = profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL,
isNight = currentWeatherData?.isNight == true
) )
} }
@ -239,7 +240,8 @@ fun WeatherScreen(onFinish: () -> Unit) {
distance = distanceFromCurrent, distance = distanceFromCurrent,
includeDistanceLabel = true, includeDistanceLabel = true,
precipitationProbability = weatherData?.precipitationProbability?.toInt() ?: 0, precipitationProbability = weatherData?.precipitationProbability?.toInt() ?: 0,
isImperial = profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL isImperial = profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL,
isNight = weatherData?.isNight == true,
) )
} }

View File

@ -46,7 +46,8 @@ fun WeatherWidget(
distance: Double? = null, distance: Double? = null,
includeDistanceLabel: Boolean = false, includeDistanceLabel: Boolean = false,
precipitationProbability: Int? = null, precipitationProbability: Int? = null,
isImperial: Boolean isImperial: Boolean,
isNight: Boolean
) { ) {
val fontSize = 20.sp val fontSize = 20.sp
@ -99,7 +100,7 @@ fun WeatherWidget(
// Weather icon (larger) // Weather icon (larger)
Icon( Icon(
painter = painterResource(id = getWeatherIcon(current)), painter = painterResource(id = getWeatherIcon(current, isNight)),
contentDescription = "Current weather", contentDescription = "Current weather",
modifier = Modifier.size(72.dp) modifier = Modifier.size(72.dp)
) )

View File

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

View File

@ -17,6 +17,7 @@ data class OpenMeteoWeatherData(
@SerialName("wind_direction_10m") val windDirection: Double, @SerialName("wind_direction_10m") val windDirection: Double,
@SerialName("wind_gusts_10m") val windGusts: Double, @SerialName("wind_gusts_10m") val windGusts: Double,
@SerialName("weather_code") val weatherCode: Int, @SerialName("weather_code") val weatherCode: Int,
@SerialName("is_day") val isDay: Int,
) { ) {
fun toWeatherData(): WeatherData = WeatherData( fun toWeatherData(): WeatherData = WeatherData(
temperature = temperature, temperature = temperature,
@ -31,6 +32,7 @@ data class OpenMeteoWeatherData(
weatherCode = weatherCode, weatherCode = weatherCode,
time = time, time = time,
isForecast = false, isForecast = false,
isNight = isDay == 0
) )
} }

View File

@ -14,7 +14,8 @@ data class OpenMeteoWeatherForecastData(
@SerialName("wind_speed_10m") val windSpeed: List<Double>, @SerialName("wind_speed_10m") val windSpeed: List<Double>,
@SerialName("wind_direction_10m") val windDirection: List<Double>, @SerialName("wind_direction_10m") val windDirection: List<Double>,
@SerialName("wind_gusts_10m") val windGusts: List<Double>, @SerialName("wind_gusts_10m") val windGusts: List<Double>,
) { @SerialName("is_day") val isDay: List<Int>,
) {
fun toWeatherData(): List<WeatherData> { fun toWeatherData(): List<WeatherData> {
return time.mapIndexed { index, t -> return time.mapIndexed { index, t ->
WeatherData( WeatherData(
@ -25,6 +26,7 @@ data class OpenMeteoWeatherForecastData(
windDirection = windDirection[index], windDirection = windDirection[index],
windGusts = windGusts[index], windGusts = windGusts[index],
weatherCode = weatherCode[index], weatherCode = weatherCode[index],
isNight = isDay[index] == 0,
time = t, time = t,
isForecast = true, isForecast = true,
) )

View File

@ -34,10 +34,10 @@ class OpenMeteoWeatherProvider : WeatherProvider {
val windUnit = if (profile?.preferredUnit?.distance != UserProfile.PreferredUnit.UnitType.IMPERIAL) WindUnit.KILOMETERS_PER_HOUR else WindUnit.MILES_PER_HOUR val windUnit = if (profile?.preferredUnit?.distance != UserProfile.PreferredUnit.UnitType.IMPERIAL) WindUnit.KILOMETERS_PER_HOUR else WindUnit.MILES_PER_HOUR
val response = callbackFlow { val response = callbackFlow {
// https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41&current=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 // 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 lats = gpsCoordinates.joinToString(",") { String.format(Locale.US, "%.6f", it.lat) }
val lons = gpsCoordinates.joinToString(",") { String.format(Locale.US, "%.6f", it.lon) } 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=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=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&timeformat=unixtime&past_hours=0&forecast_days=1&forecast_hours=12&wind_speed_unit=${windUnit.id}&precipitation_unit=${precipitationUnit.id}&temperature_unit=${temperatureUnit.id}"
Log.d(KarooHeadwindExtension.TAG, "Http request to ${url}...") Log.d(KarooHeadwindExtension.TAG, "Http request to ${url}...")

View File

@ -2,6 +2,8 @@ package de.timklge.karooheadwind.weatherprovider.openweathermap
import de.timklge.karooheadwind.weatherprovider.WeatherData import de.timklge.karooheadwind.weatherprovider.WeatherData
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import java.time.Instant
import java.time.ZoneOffset
@Serializable @Serializable
data class OpenWeatherMapForecastData( data class OpenWeatherMapForecastData(
@ -20,7 +22,16 @@ data class OpenWeatherMapForecastData(
val snow: Snow? = null, val snow: Snow? = null,
val weather: List<Weather> val weather: List<Weather>
) { ) {
fun toWeatherData(): WeatherData = WeatherData( fun toWeatherData(currentWeatherData: OpenWeatherMapWeatherData): WeatherData {
val dtInstant = Instant.ofEpochSecond(dt)
val sunriseInstant = Instant.ofEpochSecond(currentWeatherData.sunrise)
val sunsetInstant = Instant.ofEpochSecond(currentWeatherData.sunset)
val dtTime = dtInstant.atZone(ZoneOffset.UTC).toLocalTime()
val sunriseTime = sunriseInstant.atZone(ZoneOffset.UTC).toLocalTime()
val sunsetTime = sunsetInstant.atZone(ZoneOffset.UTC).toLocalTime()
return WeatherData(
temperature = temp, temperature = temp,
relativeHumidity = humidity.toDouble(), relativeHumidity = humidity.toDouble(),
precipitation = rain?.h1 ?: 0.0, precipitation = rain?.h1 ?: 0.0,
@ -34,6 +45,8 @@ data class OpenWeatherMapForecastData(
weather.firstOrNull()?.id ?: 800 weather.firstOrNull()?.id ?: 800
), ),
time = dt, time = dt,
isForecast = true isForecast = true,
isNight = dtTime.isBefore(sunriseTime) || dtTime.isAfter(sunsetTime)
) )
}
} }

View File

@ -35,6 +35,9 @@ data class OpenWeatherMapWeatherData(
weather.firstOrNull()?.id ?: 800 weather.firstOrNull()?.id ?: 800
), ),
time = dt, time = dt,
isNight = let {
dt !in sunrise..<sunset
},
isForecast = false isForecast = false
) )
} }

View File

@ -14,10 +14,17 @@ data class OpenWeatherMapWeatherDataForLocation(
val current: OpenWeatherMapWeatherData, val current: OpenWeatherMapWeatherData,
val hourly: List<OpenWeatherMapForecastData> val hourly: List<OpenWeatherMapForecastData>
){ ){
fun toWeatherDataForLocation(distanceAlongRoute: Double?): WeatherDataForLocation = WeatherDataForLocation( fun toWeatherDataForLocation(distanceAlongRoute: Double?): WeatherDataForLocation {
return WeatherDataForLocation(
current = current.toWeatherData(), current = current.toWeatherData(),
coords = GpsCoordinates(lat, lon, bearing = null, distanceAlongRoute = distanceAlongRoute), coords = GpsCoordinates(
lat,
lon,
bearing = null,
distanceAlongRoute = distanceAlongRoute
),
timezone = timezone, timezone = timezone,
forecasts = hourly.map { it.toWeatherData() } forecasts = hourly.map { it.toWeatherData(current) }
) )
}
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB