Zepp OS: Adjust weather v5 responses

This commit is contained in:
José Rebelo
2026-01-24 14:09:20 +00:00
parent 9dd91c4349
commit b7ce6a67e8
3 changed files with 93 additions and 29 deletions
@@ -7,12 +7,15 @@ import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec
import nodomain.freeyourgadget.gadgetbridge.model.weather.Weather.getWeatherSpec import nodomain.freeyourgadget.gadgetbridge.model.weather.Weather.getWeatherSpec
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsWeatherHandler import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsWeatherHandler
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils
import nodomain.freeyourgadget.gadgetbridge.util.gson.DoubleAdapter
import nodomain.freeyourgadget.gadgetbridge.util.gson.FloatAdapter
import nodomain.freeyourgadget.gadgetbridge.util.gson.OffsetDateTimeAdapter import nodomain.freeyourgadget.gadgetbridge.util.gson.OffsetDateTimeAdapter
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.time.Instant import java.time.Instant
import java.time.OffsetDateTime import java.time.OffsetDateTime
import java.time.ZoneId import java.time.ZoneId
import java.util.Calendar
import java.util.Date import java.util.Date
import java.util.GregorianCalendar import java.util.GregorianCalendar
import kotlin.math.roundToInt import kotlin.math.roundToInt
@@ -24,6 +27,8 @@ object ZeppOsWeatherHandlerV5 {
private val GSON: Gson = GsonBuilder() private val GSON: Gson = GsonBuilder()
.serializeNulls() .serializeNulls()
.registerTypeAdapter(OffsetDateTime::class.java, OffsetDateTimeAdapter()) .registerTypeAdapter(OffsetDateTime::class.java, OffsetDateTimeAdapter())
.registerTypeAdapter(Float::class.java, FloatAdapter)
.registerTypeAdapter(Double::class.java, DoubleAdapter)
.create() .create()
@JvmStatic @JvmStatic
@@ -114,12 +119,13 @@ object ZeppOsWeatherHandlerV5 {
) )
} }
private fun createHourlyAirQuality(weatherSpec: WeatherSpec): HourlyAirQuality { private fun createHourlyAirQuality(weatherSpec: WeatherSpec): Any {
// TODO WeatherSpec does not support hourly air quality // TODO WeatherSpec does not support hourly air quality
return HourlyAirQuality( return EmptyResponse()
metadata = createMetadata(weatherSpec), //return HourlyAirQuality(
hours = emptyList() // metadata = createMetadata(weatherSpec),
) // hours = emptyList()
//)
} }
private fun createDailyIndices(weatherSpec: WeatherSpec): DailyIndices { private fun createDailyIndices(weatherSpec: WeatherSpec): DailyIndices {
@@ -151,6 +157,26 @@ object ZeppOsWeatherHandlerV5 {
val sunrise = WeatherSpec.sunriseComputed(day.sunRise, calendar, weatherSpec.getLocationObject()) val sunrise = WeatherSpec.sunriseComputed(day.sunRise, calendar, weatherSpec.getLocationObject())
val sunset = WeatherSpec.sunsetComputed(day.sunRise, calendar, weatherSpec.getLocationObject()) val sunset = WeatherSpec.sunsetComputed(day.sunRise, calendar, weatherSpec.getLocationObject())
val daytimeForecastStart: Date
val daytimeForecastEnd: Date
if (sunrise != null && sunset != null) {
daytimeForecastStart = sunrise
daytimeForecastEnd = sunset
} else {
// We do not have sunrise and sunset.. use averages for now
val calendar = Calendar.getInstance()
calendar.setTime(Date(dayTimestamp))
calendar.set(Calendar.HOUR_OF_DAY, 6)
daytimeForecastStart = calendar.time
calendar.setTime(Date(dayTimestamp))
calendar.set(Calendar.HOUR_OF_DAY, 18)
daytimeForecastEnd = calendar.time
}
val nightDurationSeconds = 3600 * 24 - ((daytimeForecastEnd.time - daytimeForecastStart.time) / 1000L)
DailyWeatherDay( DailyWeatherDay(
forecastStart = toOffsetDateTime(DateTimeUtils.dayStart(Date(dayTimestamp))), forecastStart = toOffsetDateTime(DateTimeUtils.dayStart(Date(dayTimestamp))),
forecastEnd = toOffsetDateTime(DateTimeUtils.dayEnd(Date(dayTimestamp))), forecastEnd = toOffsetDateTime(DateTimeUtils.dayEnd(Date(dayTimestamp))),
@@ -164,26 +190,24 @@ object ZeppOsWeatherHandlerV5 {
sunset = sunset?.let { toOffsetDateTime(it) }, sunset = sunset?.let { toOffsetDateTime(it) },
temperatureMax = day.maxTemp - 273.15f, temperatureMax = day.maxTemp - 273.15f,
temperatureMin = day.minTemp - 273.15f, temperatureMin = day.minTemp - 273.15f,
daytimeForecast = null, daytimeForecast = DayPartForecast(
overnightForecast = null, forecastStart = toOffsetDateTime(daytimeForecastStart),
//daytimeForecast = DayPartForecast( forecastEnd = toOffsetDateTime(daytimeForecastEnd),
// forecastStart = sunrise, conditionCode = ZeppOsWeatherHandler.mapToZeppOsWeatherCode(day.conditionCode).toString(),
// forecastEnd = sunset, humidity = day.humidity / 100.0f,
// conditionCode = ZeppOsWeatherHandler.mapToZeppOsWeatherCode(day.conditionCode).toString(), windDirection = day.windDirection,
// humidity = day.humidity / 100.0f, windSpeed = day.windSpeed,
// windDirection = day.windDirection, windScale = day.windSpeedAsBeaufort(),
// windSpeed = day.windSpeed, ),
// windScale = day.windSpeedAsBeaufort(), overnightForecast = DayPartForecast(
//), forecastStart = toOffsetDateTime(daytimeForecastEnd),
//overnightForecast = DayPartForecast( forecastEnd = toOffsetDateTime(daytimeForecastEnd).plusSeconds(nightDurationSeconds),
// forecastStart = sunset, conditionCode = ZeppOsWeatherHandler.mapToZeppOsWeatherCode(day.conditionCode).toString(),
// forecastEnd = Date(sunrise.time + 86400_000L), humidity = day.humidity / 100.0f,
// conditionCode = ZeppOsWeatherHandler.mapToZeppOsWeatherCode(day.conditionCode).toString(), windDirection = day.windDirection,
// humidity = day.humidity / 100.0f, windSpeed = day.windSpeed,
// windDirection = day.windDirection, windScale = day.windSpeedAsBeaufort(),
// windSpeed = day.windSpeed, ),
// windScale = day.windSpeedAsBeaufort(),
//),
) )
} }
) )
@@ -196,10 +220,8 @@ object ZeppOsWeatherHandlerV5 {
) )
} }
private fun createDailyTide(weatherSpec: WeatherSpec) = DailyTide( private fun createDailyTide(weatherSpec: WeatherSpec) = EmptyResponse(
// We do not support tide data // We do not support tide data yet
metadata = createMetadata(weatherSpec),
days = emptyList()
) )
private fun getMoonPhaseString(moonPhase: Int): String = when (moonPhase) { private fun getMoonPhaseString(moonPhase: Int): String = when (moonPhase) {
@@ -335,4 +357,6 @@ object ZeppOsWeatherHandlerV5 {
val metadata: Metadata, val metadata: Metadata,
val days: List<DailyTideDay>, val days: List<DailyTideDay>,
) )
class EmptyResponse
} }
@@ -0,0 +1,20 @@
package nodomain.freeyourgadget.gadgetbridge.util.gson
import com.google.gson.TypeAdapter
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter
import java.util.Locale
object DoubleAdapter : TypeAdapter<Double>() {
override fun write(out: JsonWriter, value: Double?) {
if (value == null) {
out.nullValue()
} else {
out.value(String.format(Locale.ROOT, "%.2f", value).toDouble())
}
}
override fun read(input: JsonReader): Double {
return input.nextDouble()
}
}
@@ -0,0 +1,20 @@
package nodomain.freeyourgadget.gadgetbridge.util.gson
import com.google.gson.TypeAdapter
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter
import java.util.Locale
object FloatAdapter : TypeAdapter<Float>() {
override fun write(out: JsonWriter, value: Float?) {
if (value == null) {
out.nullValue()
} else {
out.value(String.format(Locale.ROOT, "%.2f", value).toFloat())
}
}
override fun read(input: JsonReader): Float {
return input.nextDouble().toFloat()
}
}