From 96bee1b55c2e23d7bc3d88b1c5c4cabfdf54dcb1 Mon Sep 17 00:00:00 2001 From: timklge <2026103+timklge@users.noreply.github.com> Date: Mon, 5 May 2025 21:26:55 +0200 Subject: [PATCH] Add moon icon to represent clear sky at night (#123) --- .../de/timklge/karooheadwind/DataStore.kt | 3 +- .../timklge/karooheadwind/HeadwindSettings.kt | 1 - .../datatypes/ForecastDataType.kt | 23 +++++---- .../datatypes/GraphicalForecast.kt | 11 ++-- .../PrecipitationForecastDataType.kt | 8 +-- .../datatypes/TemperatureForecastDataType.kt | 5 +- .../datatypes/WeatherDataType.kt | 15 ++++-- .../datatypes/WeatherForecastDataType.kt | 6 ++- .../karooheadwind/datatypes/WeatherView.kt | 9 ++-- .../datatypes/WindForecastDataType.kt | 5 +- .../karooheadwind/screens/WeatherScreen.kt | 4 +- .../karooheadwind/screens/WeatherWidget.kt | 5 +- .../weatherprovider/WeatherData.kt | 3 +- .../openmeteo/OpenMeteoWeatherData.kt | 2 + .../openmeteo/OpenMeteoWeatherForecastData.kt | 4 +- .../openmeteo/OpenMeteoWeatherProvider.kt | 4 +- .../OpenWeatherMapForecastData.kt | 47 +++++++++++------- .../OpenWeatherMapWeatherData.kt | 3 ++ .../OpenWeatherMapWeatherDataForLocation.kt | 19 ++++--- app/src/main/res/drawable/moon.png | Bin 0 -> 5750 bytes 20 files changed, 113 insertions(+), 64 deletions(-) create mode 100644 app/src/main/res/drawable/moon.png diff --git a/app/src/main/kotlin/de/timklge/karooheadwind/DataStore.kt b/app/src/main/kotlin/de/timklge/karooheadwind/DataStore.kt index 5e8ddd4..ef03232 100644 --- a/app/src/main/kotlin/de/timklge/karooheadwind/DataStore.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/DataStore.kt @@ -276,7 +276,8 @@ fun lerpWeather( windDirection = lerpAngle(start.windDirection, end.windDirection, factor), windGusts = start.windGusts + (end.windGusts - start.windGusts) * factor, weatherCode = closestWeatherData.weatherCode, - isForecast = closestWeatherData.isForecast + isForecast = closestWeatherData.isForecast, + isNight = closestWeatherData.isNight, ) } diff --git a/app/src/main/kotlin/de/timklge/karooheadwind/HeadwindSettings.kt b/app/src/main/kotlin/de/timklge/karooheadwind/HeadwindSettings.kt index 71f24bf..f5cd6ec 100644 --- a/app/src/main/kotlin/de/timklge/karooheadwind/HeadwindSettings.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/HeadwindSettings.kt @@ -50,7 +50,6 @@ data class HeadwindWidgetSettings( } } -//Moded with openweahtermap.org @Serializable data class HeadwindStats( val lastSuccessfulWeatherRequest: Long? = null, diff --git a/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/ForecastDataType.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/ForecastDataType.kt index 3da7aea..43549aa 100644 --- a/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/ForecastDataType.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/ForecastDataType.kt @@ -28,11 +28,7 @@ import de.timklge.karooheadwind.KarooHeadwindExtension import de.timklge.karooheadwind.R import de.timklge.karooheadwind.TemperatureUnit 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.weatherprovider.WeatherDataResponse -import de.timklge.karooheadwind.weatherprovider.WeatherInterpretation import de.timklge.karooheadwind.getHeadingFlow import de.timklge.karooheadwind.streamCurrentForecastWeatherData import de.timklge.karooheadwind.streamSettings @@ -40,6 +36,10 @@ import de.timklge.karooheadwind.streamUpcomingRoute import de.timklge.karooheadwind.streamUserProfile import de.timklge.karooheadwind.streamWidgetSettings 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.extension.DataTypeImpl import io.hammerhead.karooext.internal.ViewEmitter @@ -78,7 +78,8 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ timeLabel: String, dateLabel: String?, distance: Double?, - isImperial: Boolean) + isImperial: Boolean, + isNight: Boolean) @OptIn(ExperimentalGlanceRemoteViewsApi::class) private val glance = GlanceRemoteViews() @@ -123,7 +124,8 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ windDirection = forecastWindDirection, windGusts = forecastWindGusts, weatherCode = forecastWeatherCode, - isForecast = true + isForecast = true, + isNight = it < 2 ) } @@ -144,7 +146,8 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ windDirection = 180.0, windGusts = 10.0, weatherCode = WeatherInterpretation.getKnownWeatherCodes().random(), - isForecast = false + isForecast = false, + isNight = false ), coords = GpsCoordinates(0.0, 0.0, distanceAlongRoute = index * distancePerHour), timezone = "UTC", @@ -305,7 +308,8 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ timeLabel = formattedTime, dateLabel = if (hasNewDate) formattedDate else null, distance = null, - isImperial = settingsAndProfile.isImperial + isImperial = settingsAndProfile.isImperial, + isNight = data.current.isNight ) previousDate = formattedDate @@ -330,7 +334,8 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ timeLabel = formattedTime, dateLabel = if (hasNewDate) formattedDate else null, distance = if (settingsAndProfile.settings.showDistanceInForecast) distanceFromCurrent else null, - isImperial = settingsAndProfile.isImperial + isImperial = settingsAndProfile.isImperial, + isNight = weatherData?.isNight == true ) previousDate = formattedDate diff --git a/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/GraphicalForecast.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/GraphicalForecast.kt index 3d081af..35b86c6 100644 --- a/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/GraphicalForecast.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/GraphicalForecast.kt @@ -34,13 +34,14 @@ fun GraphicalForecast( distance: Double? = null, timeLabel: String? = null, rowAlignment: Alignment.Horizontal = Alignment.Horizontal.CenterHorizontally, - isImperial: Boolean? + isImperial: Boolean?, + isNight: Boolean, ) { Column(modifier = GlanceModifier.fillMaxHeight().padding(1.dp).width(86.dp), horizontalAlignment = rowAlignment) { Row(modifier = GlanceModifier.defaultWeight().wrapContentWidth(), horizontalAlignment = rowAlignment, verticalAlignment = Alignment.CenterVertically) { Image( modifier = GlanceModifier.defaultWeight().wrapContentWidth().padding(1.dp), - provider = ImageProvider(getWeatherIcon(current)), + provider = ImageProvider(getWeatherIcon(current, isNight)), contentDescription = "Current weather information", contentScale = ContentScale.Fit, colorFilter = ColorFilter.tint(ColorProvider(Color.Black, Color.White)) @@ -96,13 +97,15 @@ class GraphicalForecastDataType(karooSystem: KarooSystemService) : ForecastDataT timeLabel: String, dateLabel: String?, distance: Double?, - isImperial: Boolean + isImperial: Boolean, + isNight: Boolean, ) { GraphicalForecast( current = current, distance = distance, timeLabel = timeLabel, - isImperial = isImperial + isImperial = isImperial, + isNight = isNight ) } } \ No newline at end of file diff --git a/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/PrecipitationForecastDataType.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/PrecipitationForecastDataType.kt index 39371c7..85d57e0 100644 --- a/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/PrecipitationForecastDataType.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/PrecipitationForecastDataType.kt @@ -25,7 +25,6 @@ import de.timklge.karooheadwind.weatherprovider.WeatherInterpretation import io.hammerhead.karooext.KarooSystemService import kotlin.math.absoluteValue import kotlin.math.ceil -import kotlin.math.roundToInt @Composable fun PrecipitationForecast( @@ -34,7 +33,7 @@ fun PrecipitationForecast( distance: Double? = null, timeLabel: String? = null, rowAlignment: Alignment.Horizontal = Alignment.Horizontal.CenterHorizontally, - isImperial: Boolean? + isImperial: Boolean?, ) { Column(modifier = GlanceModifier.fillMaxHeight().padding(1.dp).width(86.dp), horizontalAlignment = rowAlignment) { Row(modifier = GlanceModifier.defaultWeight().fillMaxWidth(), horizontalAlignment = rowAlignment, verticalAlignment = Alignment.CenterVertically) { @@ -95,14 +94,15 @@ class PrecipitationForecastDataType(karooSystem: KarooSystemService) : ForecastD timeLabel: String, dateLabel: String?, distance: Double?, - isImperial: Boolean + isImperial: Boolean, + isNight: Boolean, ) { PrecipitationForecast( precipitation = ceil(precipitation).toInt(), precipitationProbability = precipitationProbability, distance = distance, timeLabel = timeLabel, - isImperial = isImperial + isImperial = isImperial, ) } } \ No newline at end of file diff --git a/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/TemperatureForecastDataType.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/TemperatureForecastDataType.kt index 165dc25..31bffea 100644 --- a/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/TemperatureForecastDataType.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/TemperatureForecastDataType.kt @@ -91,14 +91,15 @@ class TemperatureForecastDataType(karooSystem: KarooSystemService) : ForecastDat timeLabel: String, dateLabel: String?, distance: Double?, - isImperial: Boolean + isImperial: Boolean, + isNight: Boolean ) { TemperatureForecast( temperature = temperature, temperatureUnit = temperatureUnit, distance = distance, timeLabel = timeLabel, - isImperial = isImperial + isImperial = isImperial, ) } } diff --git a/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherDataType.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherDataType.kt index 2f8e826..e11ba2b 100644 --- a/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherDataType.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherDataType.kt @@ -16,6 +16,7 @@ import de.timklge.karooheadwind.HeadingResponse import de.timklge.karooheadwind.HeadwindSettings import de.timklge.karooheadwind.KarooHeadwindExtension import de.timklge.karooheadwind.MainActivity +import de.timklge.karooheadwind.R import de.timklge.karooheadwind.TemperatureUnit import de.timklge.karooheadwind.getHeadingFlow import de.timklge.karooheadwind.streamCurrentWeatherData @@ -79,9 +80,12 @@ class WeatherDataType( private fun previewFlow(): Flow = flow { while (true){ 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, - WeatherInterpretation.getKnownWeatherCodes().random(), isForecast = false), HeadwindSettings())) + WeatherData( + Instant.now().epochSecond, 0.0, + 20.0, 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())) delay(5_000) } @@ -96,7 +100,7 @@ class WeatherDataType( val baseBitmap = BitmapFactory.decodeResource( context.resources, - de.timklge.karooheadwind.R.drawable.arrow_0 + R.drawable.arrow_0 ) val dataFlow = if (config.preview){ @@ -148,7 +152,8 @@ class WeatherDataType( }, dateLabel = formattedDate, singleDisplay = true, - isImperial = userProfile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL + isImperial = userProfile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL, + isNight = data.isNight, ) } } diff --git a/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherForecastDataType.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherForecastDataType.kt index e7d32e3..7d6f3d2 100644 --- a/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherForecastDataType.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherForecastDataType.kt @@ -21,7 +21,8 @@ class WeatherForecastDataType(karooSystem: KarooSystemService) : ForecastDataTyp timeLabel: String, dateLabel: String?, distance: Double?, - isImperial: Boolean + isImperial: Boolean, + isNight: Boolean, ) { Weather( arrowBitmap = arrowBitmap, @@ -36,7 +37,8 @@ class WeatherForecastDataType(karooSystem: KarooSystemService) : ForecastDataTyp timeLabel = timeLabel, dateLabel = dateLabel, distance = distance, - isImperial = isImperial + isImperial = isImperial, + isNight = isNight, ) } diff --git a/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherView.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherView.kt index dbf0b73..10dd506 100644 --- a/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherView.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherView.kt @@ -45,9 +45,9 @@ fun getShortDateFormatter(): DateTimeFormatter = DateTimeFormatter.ofPattern( } ).withZone(ZoneId.systemDefault()) -fun getWeatherIcon(interpretation: WeatherInterpretation): Int { +fun getWeatherIcon(interpretation: WeatherInterpretation, isNight: Boolean): Int { 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.RAINY -> R.drawable.bx_cloud_rain WeatherInterpretation.SNOWY -> R.drawable.bx_cloud_snow @@ -74,7 +74,8 @@ fun Weather( rowAlignment: Alignment.Horizontal = Alignment.Horizontal.CenterHorizontally, dateLabel: String? = null, singleDisplay: Boolean = false, - isImperial: Boolean? + isImperial: Boolean?, + isNight: Boolean ) { val fontSize = if (singleDisplay) 19f else 14f @@ -83,7 +84,7 @@ fun Weather( Row(modifier = GlanceModifier.defaultWeight().wrapContentWidth(), horizontalAlignment = rowAlignment, verticalAlignment = Alignment.CenterVertically) { Image( modifier = GlanceModifier.defaultWeight().wrapContentWidth().padding(1.dp), - provider = ImageProvider(getWeatherIcon(current)), + provider = ImageProvider(getWeatherIcon(current, isNight)), contentDescription = "Current weather information", contentScale = ContentScale.Fit, colorFilter = ColorFilter.tint(ColorProvider(Color.Black, Color.White)) diff --git a/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WindForecastDataType.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WindForecastDataType.kt index 3507a29..36ce287 100644 --- a/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WindForecastDataType.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WindForecastDataType.kt @@ -103,7 +103,8 @@ class WindForecastDataType(karooSystem: KarooSystemService) : ForecastDataType(k timeLabel: String, dateLabel: String?, distance: Double?, - isImperial: Boolean + isImperial: Boolean, + isNight: Boolean ) { WindForecast( arrowBitmap = arrowBitmap, @@ -112,7 +113,7 @@ class WindForecastDataType(karooSystem: KarooSystemService) : ForecastDataType(k gustSpeed = windGusts, distance = distance, timeLabel = timeLabel, - isImperial = isImperial + isImperial = isImperial, ) } } \ No newline at end of file diff --git a/app/src/main/kotlin/de/timklge/karooheadwind/screens/WeatherScreen.kt b/app/src/main/kotlin/de/timklge/karooheadwind/screens/WeatherScreen.kt index ec67a7c..66c1449 100644 --- a/app/src/main/kotlin/de/timklge/karooheadwind/screens/WeatherScreen.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/screens/WeatherScreen.kt @@ -120,6 +120,7 @@ fun WeatherScreen(onFinish: () -> Unit) { distance = requestedWeatherPosition?.let { l -> location?.distanceTo(l)?.times(1000) }, includeDistanceLabel = false, isImperial = profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL, + isNight = currentWeatherData?.isNight == true ) } @@ -239,7 +240,8 @@ fun WeatherScreen(onFinish: () -> Unit) { distance = distanceFromCurrent, includeDistanceLabel = true, 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, ) } diff --git a/app/src/main/kotlin/de/timklge/karooheadwind/screens/WeatherWidget.kt b/app/src/main/kotlin/de/timklge/karooheadwind/screens/WeatherWidget.kt index 7854b2b..00ea0cf 100644 --- a/app/src/main/kotlin/de/timklge/karooheadwind/screens/WeatherWidget.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/screens/WeatherWidget.kt @@ -46,7 +46,8 @@ fun WeatherWidget( distance: Double? = null, includeDistanceLabel: Boolean = false, precipitationProbability: Int? = null, - isImperial: Boolean + isImperial: Boolean, + isNight: Boolean ) { val fontSize = 20.sp @@ -99,7 +100,7 @@ fun WeatherWidget( // Weather icon (larger) Icon( - painter = painterResource(id = getWeatherIcon(current)), + painter = painterResource(id = getWeatherIcon(current, isNight)), contentDescription = "Current weather", modifier = Modifier.size(72.dp) ) diff --git a/app/src/main/kotlin/de/timklge/karooheadwind/weatherprovider/WeatherData.kt b/app/src/main/kotlin/de/timklge/karooheadwind/weatherprovider/WeatherData.kt index 1886e91..ede008e 100644 --- a/app/src/main/kotlin/de/timklge/karooheadwind/weatherprovider/WeatherData.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/weatherprovider/WeatherData.kt @@ -16,6 +16,7 @@ data class WeatherData( val windDirection: Double, val windGusts: Double, val weatherCode: Int, - val isForecast: Boolean + val isForecast: Boolean, + val isNight: Boolean ) diff --git a/app/src/main/kotlin/de/timklge/karooheadwind/weatherprovider/openmeteo/OpenMeteoWeatherData.kt b/app/src/main/kotlin/de/timklge/karooheadwind/weatherprovider/openmeteo/OpenMeteoWeatherData.kt index 1c66122..a1a4218 100644 --- a/app/src/main/kotlin/de/timklge/karooheadwind/weatherprovider/openmeteo/OpenMeteoWeatherData.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/weatherprovider/openmeteo/OpenMeteoWeatherData.kt @@ -17,6 +17,7 @@ data class OpenMeteoWeatherData( @SerialName("wind_direction_10m") val windDirection: Double, @SerialName("wind_gusts_10m") val windGusts: Double, @SerialName("weather_code") val weatherCode: Int, + @SerialName("is_day") val isDay: Int, ) { fun toWeatherData(): WeatherData = WeatherData( temperature = temperature, @@ -31,6 +32,7 @@ data class OpenMeteoWeatherData( weatherCode = weatherCode, time = time, isForecast = false, + isNight = isDay == 0 ) } diff --git a/app/src/main/kotlin/de/timklge/karooheadwind/weatherprovider/openmeteo/OpenMeteoWeatherForecastData.kt b/app/src/main/kotlin/de/timklge/karooheadwind/weatherprovider/openmeteo/OpenMeteoWeatherForecastData.kt index 72d1ffa..7c4c375 100644 --- a/app/src/main/kotlin/de/timklge/karooheadwind/weatherprovider/openmeteo/OpenMeteoWeatherForecastData.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/weatherprovider/openmeteo/OpenMeteoWeatherForecastData.kt @@ -14,7 +14,8 @@ data class OpenMeteoWeatherForecastData( @SerialName("wind_speed_10m") val windSpeed: List, @SerialName("wind_direction_10m") val windDirection: List, @SerialName("wind_gusts_10m") val windGusts: List, -) { + @SerialName("is_day") val isDay: List, + ) { fun toWeatherData(): List { return time.mapIndexed { index, t -> WeatherData( @@ -25,6 +26,7 @@ data class OpenMeteoWeatherForecastData( windDirection = windDirection[index], windGusts = windGusts[index], weatherCode = weatherCode[index], + isNight = isDay[index] == 0, time = t, isForecast = true, ) diff --git a/app/src/main/kotlin/de/timklge/karooheadwind/weatherprovider/openmeteo/OpenMeteoWeatherProvider.kt b/app/src/main/kotlin/de/timklge/karooheadwind/weatherprovider/openmeteo/OpenMeteoWeatherProvider.kt index a865993..b8eff6b 100644 --- a/app/src/main/kotlin/de/timklge/karooheadwind/weatherprovider/openmeteo/OpenMeteoWeatherProvider.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/weatherprovider/openmeteo/OpenMeteoWeatherProvider.kt @@ -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 response = callbackFlow { - // https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41¤t=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¤t=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}¤t=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}¤t=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}...") diff --git a/app/src/main/kotlin/de/timklge/karooheadwind/weatherprovider/openweathermap/OpenWeatherMapForecastData.kt b/app/src/main/kotlin/de/timklge/karooheadwind/weatherprovider/openweathermap/OpenWeatherMapForecastData.kt index 1591b84..e09b8d0 100644 --- a/app/src/main/kotlin/de/timklge/karooheadwind/weatherprovider/openweathermap/OpenWeatherMapForecastData.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/weatherprovider/openweathermap/OpenWeatherMapForecastData.kt @@ -2,6 +2,8 @@ package de.timklge.karooheadwind.weatherprovider.openweathermap import de.timklge.karooheadwind.weatherprovider.WeatherData import kotlinx.serialization.Serializable +import java.time.Instant +import java.time.ZoneOffset @Serializable data class OpenWeatherMapForecastData( @@ -20,20 +22,31 @@ data class OpenWeatherMapForecastData( val snow: Snow? = null, val weather: List ) { - fun toWeatherData(): WeatherData = WeatherData( - temperature = temp, - relativeHumidity = humidity.toDouble(), - precipitation = rain?.h1 ?: 0.0, - cloudCover = clouds.toDouble(), - surfacePressure = pressure.toDouble(), - sealevelPressure = pressure.toDouble(), // FIXME - windSpeed = wind_speed, - windDirection = wind_deg.toDouble(), - windGusts = wind_gust ?: wind_speed, - weatherCode = OpenWeatherMapWeatherProvider.convertWeatherCodeToOpenMeteo( - weather.firstOrNull()?.id ?: 800 - ), - time = dt, - isForecast = true - ) -} \ No newline at end of file + 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, + relativeHumidity = humidity.toDouble(), + precipitation = rain?.h1 ?: 0.0, + cloudCover = clouds.toDouble(), + surfacePressure = pressure.toDouble(), + sealevelPressure = pressure.toDouble(), // FIXME + windSpeed = wind_speed, + windDirection = wind_deg.toDouble(), + windGusts = wind_gust ?: wind_speed, + weatherCode = OpenWeatherMapWeatherProvider.convertWeatherCodeToOpenMeteo( + weather.firstOrNull()?.id ?: 800 + ), + time = dt, + isForecast = true, + isNight = dtTime.isBefore(sunriseTime) || dtTime.isAfter(sunsetTime) + ) + } +} diff --git a/app/src/main/kotlin/de/timklge/karooheadwind/weatherprovider/openweathermap/OpenWeatherMapWeatherData.kt b/app/src/main/kotlin/de/timklge/karooheadwind/weatherprovider/openweathermap/OpenWeatherMapWeatherData.kt index fd5828b..6decf17 100644 --- a/app/src/main/kotlin/de/timklge/karooheadwind/weatherprovider/openweathermap/OpenWeatherMapWeatherData.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/weatherprovider/openweathermap/OpenWeatherMapWeatherData.kt @@ -35,6 +35,9 @@ data class OpenWeatherMapWeatherData( weather.firstOrNull()?.id ?: 800 ), time = dt, + isNight = let { + dt !in sunrise.. ){ - fun toWeatherDataForLocation(distanceAlongRoute: Double?): WeatherDataForLocation = WeatherDataForLocation( - current = current.toWeatherData(), - coords = GpsCoordinates(lat, lon, bearing = null, distanceAlongRoute = distanceAlongRoute), - timezone = timezone, - forecasts = hourly.map { it.toWeatherData() } - ) + fun toWeatherDataForLocation(distanceAlongRoute: Double?): WeatherDataForLocation { + return WeatherDataForLocation( + current = current.toWeatherData(), + coords = GpsCoordinates( + lat, + lon, + bearing = null, + distanceAlongRoute = distanceAlongRoute + ), + timezone = timezone, + forecasts = hourly.map { it.toWeatherData(current) } + ) + } } \ No newline at end of file diff --git a/app/src/main/res/drawable/moon.png b/app/src/main/res/drawable/moon.png new file mode 100644 index 0000000000000000000000000000000000000000..318344ab8c0c329c7c2eddbbf471dc40dde4e406 GIT binary patch literal 5750 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 literal 0 HcmV?d00001