diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsWeatherService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsWeatherService.java index 4a04f4126e..418f52e02e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsWeatherService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsWeatherService.java @@ -21,7 +21,9 @@ import org.slf4j.LoggerFactory; import java.io.ByteArrayOutputStream; import java.nio.charset.StandardCharsets; +import java.util.Locale; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; import nodomain.freeyourgadget.gadgetbridge.model.weather.Weather; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; @@ -67,7 +69,18 @@ public class ZeppOsWeatherService extends AbstractZeppOsService { // When we have a weather update, set the default location to that location on the band. // TODO: Support for multiple weather locations - final String locationKey = "1.234,-5.678,xiaomi_accu:" + System.currentTimeMillis(); // dummy + float lat = weatherSpec.getLatitude(); + float lon = weatherSpec.getLongitude(); + if (lat == 0f && lon == 0f) { + // Some weather providers don't populate WeatherSpec coords on broadcast. + // Fall back to user-configured location pref so the watch gets a valid + // default location and accepts subsequent v5 HTTP responses (issue #5653). + lat = GBApplication.getPrefs().getFloat("location_latitude", 0f); + lon = GBApplication.getPrefs().getFloat("location_longitude", 0f); + } + final String coordKey = String.format(Locale.ROOT, "%.4f,%.4f", lat, lon); + final long locationKeyId = ((long) coordKey.hashCode()) & 0xFFFFFFFFL; + final String locationKey = String.format(Locale.ROOT, "%.4f,%.4f,xiaomi_accu:%d", lat, lon, locationKeyId); final String locationName = weatherSpec.getLocation(); try { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/http/ZeppOsWeatherHandlerV5.kt b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/http/ZeppOsWeatherHandlerV5.kt index 3ded08e37e..f0578127b5 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/http/ZeppOsWeatherHandlerV5.kt +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/http/ZeppOsWeatherHandlerV5.kt @@ -3,6 +3,7 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.servic import com.google.gson.Gson import com.google.gson.GsonBuilder import com.google.gson.JsonObject +import nodomain.freeyourgadget.gadgetbridge.GBApplication import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec import nodomain.freeyourgadget.gadgetbridge.model.weather.Weather.getWeatherSpec import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsWeatherHandler @@ -18,6 +19,7 @@ import java.time.ZoneId import java.util.Calendar import java.util.Date import java.util.GregorianCalendar +import java.util.Locale import kotlin.math.roundToInt @Suppress("unused") @@ -88,14 +90,32 @@ object ZeppOsWeatherHandlerV5 { version = 1, ) - private fun createPlace(weatherSpec: WeatherSpec) = Place( - locationKey = "accu:123456", - longitude = weatherSpec.longitude.toString(), - latitude = weatherSpec.latitude.toString(), - affiliation = weatherSpec.location, - name = weatherSpec.location, - countryCode = null, - ) + private fun createPlace(weatherSpec: WeatherSpec): Place { + val (lat, lon) = resolveCoordinates(weatherSpec) + // Stable per-location id so the watch can dedupe responses. Hash of rounded + // coords keeps it deterministic across requests for the same location. + val coordKey = String.format(Locale.ROOT, "%.4f,%.4f", lat, lon) + val locationKeyId = coordKey.hashCode().toLong() and 0xFFFFFFFFL + return Place( + locationKey = "accu:$locationKeyId", + longitude = String.format(Locale.ROOT, "%.3f", lon), + latitude = String.format(Locale.ROOT, "%.3f", lat), + affiliation = weatherSpec.location, + name = weatherSpec.location, + countryCode = null, + ) + } + + // Some weather providers don't populate WeatherSpec.latitude/longitude on broadcast. + // Fall back to the user-configured location pref so the watch gets a non-zero place, + // which it requires to accept the response as authoritative (issue #5653). + private fun resolveCoordinates(weatherSpec: WeatherSpec): Pair { + if (weatherSpec.latitude != 0f || weatherSpec.longitude != 0f) { + return weatherSpec.latitude to weatherSpec.longitude + } + val prefs = GBApplication.getPrefs() + return prefs.getFloat("location_latitude", 0f) to prefs.getFloat("location_longitude", 0f) + } private fun createHourlyWeather(weatherSpec: WeatherSpec): HourlyWeather { return HourlyWeather(