Add UV Index to current weather and forecast (#159)
This commit is contained in:
parent
be7ca192b2
commit
5169048143
@ -294,9 +294,9 @@ fun lerpWeather(
|
|||||||
weatherCode = closestWeatherData.weatherCode,
|
weatherCode = closestWeatherData.weatherCode,
|
||||||
isForecast = closestWeatherData.isForecast,
|
isForecast = closestWeatherData.isForecast,
|
||||||
isNight = closestWeatherData.isNight,
|
isNight = closestWeatherData.isNight,
|
||||||
|
uvi = start.uvi + (end.uvi - start.uvi) * factor
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun lerpWeatherTime(
|
fun lerpWeatherTime(
|
||||||
weatherData: List<WeatherData>?,
|
weatherData: List<WeatherData>?,
|
||||||
currentWeatherData: WeatherData
|
currentWeatherData: WeatherData
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import de.timklge.karooheadwind.datatypes.SealevelPressureDataType
|
|||||||
import de.timklge.karooheadwind.datatypes.SurfacePressureDataType
|
import de.timklge.karooheadwind.datatypes.SurfacePressureDataType
|
||||||
import de.timklge.karooheadwind.datatypes.TailwindAndRideSpeedDataType
|
import de.timklge.karooheadwind.datatypes.TailwindAndRideSpeedDataType
|
||||||
import de.timklge.karooheadwind.datatypes.TemperatureDataType
|
import de.timklge.karooheadwind.datatypes.TemperatureDataType
|
||||||
|
import de.timklge.karooheadwind.datatypes.UviDataType
|
||||||
import de.timklge.karooheadwind.datatypes.TemperatureForecastDataType
|
import de.timklge.karooheadwind.datatypes.TemperatureForecastDataType
|
||||||
import de.timklge.karooheadwind.datatypes.WeatherForecastDataType
|
import de.timklge.karooheadwind.datatypes.WeatherForecastDataType
|
||||||
import de.timklge.karooheadwind.datatypes.WindDirectionAndSpeedDataType
|
import de.timklge.karooheadwind.datatypes.WindDirectionAndSpeedDataType
|
||||||
@ -83,7 +84,8 @@ class KarooHeadwindExtension : KarooExtension("karoo-headwind", BuildConfig.VERS
|
|||||||
WindDirectionAndSpeedDataType(karooSystem, applicationContext),
|
WindDirectionAndSpeedDataType(karooSystem, applicationContext),
|
||||||
RelativeGradeDataType(karooSystem, applicationContext),
|
RelativeGradeDataType(karooSystem, applicationContext),
|
||||||
RelativeElevationGainDataType(karooSystem, applicationContext),
|
RelativeElevationGainDataType(karooSystem, applicationContext),
|
||||||
TemperatureDataType(karooSystem, applicationContext)
|
TemperatureDataType(karooSystem, applicationContext),
|
||||||
|
UviDataType(karooSystem, applicationContext)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -65,14 +65,14 @@ import kotlinx.coroutines.flow.flow
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.time.ZoneId
|
import java.time.ZoneId
|
||||||
import java.time.format.DateTimeFormatter
|
|
||||||
import java.time.temporal.ChronoUnit
|
import java.time.temporal.ChronoUnit
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
abstract class ForecastDataType(private val karooSystem: KarooSystemService, typeId: String) : DataTypeImpl("karoo-headwind", typeId) {
|
abstract class ForecastDataType(private val karooSystem: KarooSystemService, typeId: String) : DataTypeImpl("karoo-headwind", typeId) {
|
||||||
@Composable
|
@Composable
|
||||||
abstract fun RenderWidget(arrowBitmap: Bitmap,
|
abstract fun RenderWidget(
|
||||||
|
arrowBitmap: Bitmap,
|
||||||
current: WeatherInterpretation,
|
current: WeatherInterpretation,
|
||||||
windBearing: Int,
|
windBearing: Int,
|
||||||
windSpeed: Int,
|
windSpeed: Int,
|
||||||
@ -85,7 +85,9 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
|
|||||||
dateLabel: String?,
|
dateLabel: String?,
|
||||||
distance: Double?,
|
distance: Double?,
|
||||||
isImperial: Boolean,
|
isImperial: Boolean,
|
||||||
isNight: Boolean)
|
isNight: Boolean,
|
||||||
|
uvi: Double
|
||||||
|
)
|
||||||
|
|
||||||
@OptIn(ExperimentalGlanceRemoteViewsApi::class)
|
@OptIn(ExperimentalGlanceRemoteViewsApi::class)
|
||||||
private val glance = GlanceRemoteViews()
|
private val glance = GlanceRemoteViews()
|
||||||
@ -107,6 +109,7 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
|
|||||||
val weatherData = (0..<12).map {
|
val weatherData = (0..<12).map {
|
||||||
val forecastTime = timeAtFullHour + it * 60 * 60
|
val forecastTime = timeAtFullHour + it * 60 * 60
|
||||||
val forecastTemperature = 20.0 + (-20..20).random()
|
val forecastTemperature = 20.0 + (-20..20).random()
|
||||||
|
val forecastUvi = 0.0 + (0..12).random().toDouble()
|
||||||
val forecastPrecipitation = 0.0 + (0..10).random()
|
val forecastPrecipitation = 0.0 + (0..10).random()
|
||||||
val forecastPrecipitationProbability = (0..100).random()
|
val forecastPrecipitationProbability = (0..100).random()
|
||||||
val forecastWeatherCode = WeatherInterpretation.getKnownWeatherCodes().random()
|
val forecastWeatherCode = WeatherInterpretation.getKnownWeatherCodes().random()
|
||||||
@ -127,7 +130,8 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
|
|||||||
windGusts = forecastWindGusts,
|
windGusts = forecastWindGusts,
|
||||||
weatherCode = forecastWeatherCode,
|
weatherCode = forecastWeatherCode,
|
||||||
isForecast = true,
|
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,
|
windGusts = 10.0,
|
||||||
weatherCode = WeatherInterpretation.getKnownWeatherCodes().random(),
|
weatherCode = WeatherInterpretation.getKnownWeatherCodes().random(),
|
||||||
isForecast = false,
|
isForecast = false,
|
||||||
isNight = false
|
isNight = false,
|
||||||
|
uvi = 2.0
|
||||||
),
|
),
|
||||||
coords = GpsCoordinates(0.0, 0.0, distanceAlongRoute = index * distancePerHour),
|
coords = GpsCoordinates(0.0, 0.0, distanceAlongRoute = index * distancePerHour),
|
||||||
timezone = "UTC",
|
timezone = "UTC",
|
||||||
@ -333,7 +338,8 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
|
|||||||
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
|
isNight = data.current.isNight,
|
||||||
|
uvi = data.current.uvi
|
||||||
)
|
)
|
||||||
|
|
||||||
previousDate = formattedDate
|
previousDate = formattedDate
|
||||||
@ -359,7 +365,8 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
|
|||||||
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
|
isNight = weatherData?.isNight == true,
|
||||||
|
uvi = weatherData?.uvi ?: 0.0
|
||||||
)
|
)
|
||||||
|
|
||||||
previousDate = formattedDate
|
previousDate = formattedDate
|
||||||
|
|||||||
@ -94,6 +94,7 @@ abstract class LineGraphForecastDataType(private val karooSystem: KarooSystemSer
|
|||||||
val forecastWindSpeed = 0.0 + (0..10).random()
|
val forecastWindSpeed = 0.0 + (0..10).random()
|
||||||
val forecastWindDirection = 0.0 + (0..360).random()
|
val forecastWindDirection = 0.0 + (0..360).random()
|
||||||
val forecastWindGusts = 0.0 + (0..10).random()
|
val forecastWindGusts = 0.0 + (0..10).random()
|
||||||
|
val forcastUvi = 0.0 + (0..12).random()
|
||||||
WeatherData(
|
WeatherData(
|
||||||
time = forecastTime,
|
time = forecastTime,
|
||||||
temperature = forecastTemperature,
|
temperature = forecastTemperature,
|
||||||
@ -108,7 +109,8 @@ abstract class LineGraphForecastDataType(private val karooSystem: KarooSystemSer
|
|||||||
windGusts = forecastWindGusts,
|
windGusts = forecastWindGusts,
|
||||||
weatherCode = forecastWeatherCode,
|
weatherCode = forecastWeatherCode,
|
||||||
isForecast = true,
|
isForecast = true,
|
||||||
isNight = it < 2
|
isNight = it < 2,
|
||||||
|
uvi = forcastUvi
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,7 +132,8 @@ abstract class LineGraphForecastDataType(private val karooSystem: KarooSystemSer
|
|||||||
windGusts = 10.0,
|
windGusts = 10.0,
|
||||||
weatherCode = WeatherInterpretation.getKnownWeatherCodes().random(),
|
weatherCode = WeatherInterpretation.getKnownWeatherCodes().random(),
|
||||||
isForecast = false,
|
isForecast = false,
|
||||||
isNight = false
|
isNight = false,
|
||||||
|
uvi = 2.0
|
||||||
),
|
),
|
||||||
coords = GpsCoordinates(0.0, 0.0, distanceAlongRoute = index * distancePerHour),
|
coords = GpsCoordinates(0.0, 0.0, distanceAlongRoute = index * distancePerHour),
|
||||||
timezone = "UTC",
|
timezone = "UTC",
|
||||||
|
|||||||
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -23,6 +23,7 @@ class WeatherForecastDataType(karooSystem: KarooSystemService) : ForecastDataTyp
|
|||||||
distance: Double?,
|
distance: Double?,
|
||||||
isImperial: Boolean,
|
isImperial: Boolean,
|
||||||
isNight: Boolean,
|
isNight: Boolean,
|
||||||
|
uvi: Double,
|
||||||
) {
|
) {
|
||||||
Weather(
|
Weather(
|
||||||
arrowBitmap = arrowBitmap,
|
arrowBitmap = arrowBitmap,
|
||||||
|
|||||||
@ -17,6 +17,7 @@ data class WeatherData(
|
|||||||
val windGusts: Double,
|
val windGusts: Double,
|
||||||
val weatherCode: Int,
|
val weatherCode: Int,
|
||||||
val isForecast: Boolean,
|
val isForecast: Boolean,
|
||||||
val isNight: Boolean
|
val isNight: Boolean,
|
||||||
|
val uvi: Double,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,7 @@ data class OpenMeteoWeatherData(
|
|||||||
@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,
|
@SerialName("is_day") val isDay: Int,
|
||||||
|
@SerialName("uv_index") val uvi: Double,
|
||||||
) {
|
) {
|
||||||
fun toWeatherData(): WeatherData = WeatherData(
|
fun toWeatherData(): WeatherData = WeatherData(
|
||||||
temperature = temperature,
|
temperature = temperature,
|
||||||
@ -33,6 +34,7 @@ data class OpenMeteoWeatherData(
|
|||||||
time = time,
|
time = time,
|
||||||
isForecast = false,
|
isForecast = false,
|
||||||
isNight = isDay == 0,
|
isNight = isDay == 0,
|
||||||
|
uvi = uvi
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,6 +19,7 @@ data class OpenMeteoWeatherForecastData(
|
|||||||
@SerialName("pressure_msl") val sealevelPressure: List<Double>,
|
@SerialName("pressure_msl") val sealevelPressure: List<Double>,
|
||||||
@SerialName("is_day") val isDay: List<Int>,
|
@SerialName("is_day") val isDay: List<Int>,
|
||||||
@SerialName("relative_humidity_2m") val relativeHumidity: List<Int>,
|
@SerialName("relative_humidity_2m") val relativeHumidity: List<Int>,
|
||||||
|
@SerialName("uv_index") val uvi: List<Double>,
|
||||||
) {
|
) {
|
||||||
fun toWeatherData(): List<WeatherData> {
|
fun toWeatherData(): List<WeatherData> {
|
||||||
return time.mapIndexed { index, t ->
|
return time.mapIndexed { index, t ->
|
||||||
@ -37,6 +38,7 @@ data class OpenMeteoWeatherForecastData(
|
|||||||
surfacePressure = surfacePressure[index],
|
surfacePressure = surfacePressure[index],
|
||||||
sealevelPressure = sealevelPressure[index],
|
sealevelPressure = sealevelPressure[index],
|
||||||
relativeHumidity = relativeHumidity[index],
|
relativeHumidity = relativeHumidity[index],
|
||||||
|
uvi = uvi[index]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,7 +30,7 @@ class OpenMeteoWeatherProvider : WeatherProvider {
|
|||||||
// 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
|
// 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 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}¤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,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}¤t=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}...")
|
Log.d(KarooHeadwindExtension.TAG, "Http request to ${url}...")
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,8 @@ data class OpenWeatherMapForecastData(
|
|||||||
val pop: Double,
|
val pop: Double,
|
||||||
val rain: Rain? = null,
|
val rain: Rain? = null,
|
||||||
val snow: Snow? = null,
|
val snow: Snow? = null,
|
||||||
val weather: List<Weather>
|
val weather: List<Weather>,
|
||||||
|
val uvi: Double,
|
||||||
) {
|
) {
|
||||||
fun toWeatherData(currentWeatherData: OpenWeatherMapWeatherData): WeatherData {
|
fun toWeatherData(currentWeatherData: OpenWeatherMapWeatherData): WeatherData {
|
||||||
val dtInstant = Instant.ofEpochSecond(dt)
|
val dtInstant = Instant.ofEpochSecond(dt)
|
||||||
@ -32,6 +33,7 @@ data class OpenWeatherMapForecastData(
|
|||||||
val sunsetTime = sunsetInstant.atZone(ZoneOffset.UTC).toLocalTime()
|
val sunsetTime = sunsetInstant.atZone(ZoneOffset.UTC).toLocalTime()
|
||||||
|
|
||||||
return WeatherData(
|
return WeatherData(
|
||||||
|
uvi = uvi,
|
||||||
temperature = temp,
|
temperature = temp,
|
||||||
relativeHumidity = humidity,
|
relativeHumidity = humidity,
|
||||||
precipitation = rain?.h1 ?: 0.0,
|
precipitation = rain?.h1 ?: 0.0,
|
||||||
|
|||||||
@ -19,9 +19,11 @@ data class OpenWeatherMapWeatherData(
|
|||||||
val wind_gust: Double? = null,
|
val wind_gust: Double? = null,
|
||||||
val rain: Rain? = null,
|
val rain: Rain? = null,
|
||||||
val snow: Snow? = null,
|
val snow: Snow? = null,
|
||||||
|
val uvi: Double,
|
||||||
val weather: List<Weather>){
|
val weather: List<Weather>){
|
||||||
|
|
||||||
fun toWeatherData(): WeatherData = WeatherData(
|
fun toWeatherData(): WeatherData = WeatherData(
|
||||||
|
uvi = uvi,
|
||||||
temperature = temp,
|
temperature = temp,
|
||||||
relativeHumidity = humidity,
|
relativeHumidity = humidity,
|
||||||
precipitation = rain?.h1 ?: 0.0,
|
precipitation = rain?.h1 ?: 0.0,
|
||||||
|
|||||||
@ -22,6 +22,8 @@
|
|||||||
<string name="sealevelPressure">Sealevel pressure</string>
|
<string name="sealevelPressure">Sealevel pressure</string>
|
||||||
<string name="sealevelPressure_description">Atmospheric pressure at sea level in configured unit</string>
|
<string name="sealevelPressure_description">Atmospheric pressure at sea level in configured unit</string>
|
||||||
<string name="weather_forecast">Weather Forecast</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="weather_forecast_description">Current hourly weather forecast</string>
|
||||||
<string name="temperature_forecast">Temperature Forecast</string>
|
<string name="temperature_forecast">Temperature Forecast</string>
|
||||||
<string name="temperature_forecast_description">Current hourly temperature forecast</string>
|
<string name="temperature_forecast_description">Current hourly temperature forecast</string>
|
||||||
|
|||||||
@ -131,6 +131,13 @@
|
|||||||
icon="@drawable/thermometer"
|
icon="@drawable/thermometer"
|
||||||
typeId="temperature" />
|
typeId="temperature" />
|
||||||
|
|
||||||
|
<DataType
|
||||||
|
description="@string/uvi_description"
|
||||||
|
displayName="@string/uvi"
|
||||||
|
graphical="false"
|
||||||
|
icon="@drawable/thermometer"
|
||||||
|
typeId="uvi" />
|
||||||
|
|
||||||
<DataType
|
<DataType
|
||||||
description="@string/relativeGrade_description"
|
description="@string/relativeGrade_description"
|
||||||
displayName="@string/relativeGrade"
|
displayName="@string/relativeGrade"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user