mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
WeatherSpec: determine whether it's night
This also resolves several TODO comments in code that that previously hard-coded it to never be night, primarily in Pebble code because that's what I have for testing. In WeatherMapper, map the day and night icon variants for all condition codes, even if the reference doesn't show a difference between the two icons. Map condition 511 "freezing rain" to use icon 13 "snow" instead of icon 09 "shower rain" to match the API reference documentation.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/* Copyright (C) 2016-2024 Andreas Shimokawa, Arjan Schrijver, beardhatcode,
|
||||
/* Copyright (C) 2016-2026 Andreas Shimokawa, Arjan Schrijver, beardhatcode,
|
||||
Carsten Pfeiffer, Daniele Gobbetti, Enrico Brambilla, José Rebelo, Taavi
|
||||
Eomäe
|
||||
Eomäe, Avery Sterk
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
@@ -130,6 +130,49 @@ class WeatherSpec() : Parcelable {
|
||||
isCurrentLocation = currLoc
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the weather condition was retrieved when the sun was down
|
||||
* @return True if the weather timestamp was outside the sunrise-sunset interval
|
||||
*/
|
||||
fun isNight(): Boolean {
|
||||
return isTimeNight( this.timestamp * 1000L )
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstraction for whether the sunrise/set information indicates "polar night" (no sunrise)
|
||||
* @return True if polar night, false otherwise
|
||||
*/
|
||||
fun isPolarNight(): Boolean {
|
||||
return (this.sunSet == 0) // unix time instant of 0
|
||||
}
|
||||
/**
|
||||
* Abstraction for whether the sunrise/set information indicates "polar day" (sun never sets)
|
||||
* @return True if polar day, false otherwise
|
||||
*/
|
||||
fun isPolarDay(): Boolean {
|
||||
return ((this.sunSet - this.sunRise) >= 86399) // sun is up every second of the day
|
||||
}
|
||||
/**
|
||||
* Determines whether the current time falls during a night period based on sunrise and sunset
|
||||
* @return True if the current time of day is outside the sunset-sunrise interval
|
||||
*/
|
||||
fun isCurrentTimeNight(): Boolean {
|
||||
return isTimeNight( System.currentTimeMillis() )
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given time falls outside the sunrise-sunset interval
|
||||
* @param unixTimeMilliSeconds Unix timestamp, in UTC, in milliseconds
|
||||
* @return True if outside sunrise interval, false if during sunrise
|
||||
*/
|
||||
fun isTimeNight(unixTimeMilliSeconds: Long): Boolean {
|
||||
if (isPolarNight()) return true
|
||||
if (isPolarDay()) return false
|
||||
val millisPastMidnight = unixTimeMilliSeconds % 86400000
|
||||
if ( millisPastMidnight < (this.sunRise % 86400 * 1000L ) ) return true
|
||||
return ( millisPastMidnight > (this.sunSet % 86400 * 1000L ) )
|
||||
}
|
||||
|
||||
fun getLocationObject(): Location? {
|
||||
return if (latitude == 0f && longitude == 0f) null
|
||||
else Location("weatherSpec").apply {
|
||||
@@ -751,4 +794,4 @@ class WeatherSpec() : Parcelable {
|
||||
return weather
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-11
@@ -6,18 +6,19 @@ import nodomain.freeyourgadget.gadgetbridge.R
|
||||
object WeatherMapper {
|
||||
|
||||
@JvmStatic
|
||||
fun mapToOpenWeatherMapIcon(code: Int): String = when {
|
||||
fun mapToOpenWeatherMapIcon(code: Int, isNight: Boolean = false): String = when (code) {
|
||||
//see https://openweathermap.org/weather-conditions
|
||||
code in 200..299 -> "11d"
|
||||
code in 300..499 -> "09d"
|
||||
code in 500..509 -> "10d"
|
||||
code in 511..599 -> "09d"
|
||||
code in 600..699 -> "13d"
|
||||
code in 700..799 -> "50d"
|
||||
code == 800 -> "01d" //TODO: night?
|
||||
code == 801 -> "02d" //TODO: night?
|
||||
code == 802 -> "03d" //TODO: night?
|
||||
code == 803 || code == 804 -> "04d" //TODO: night?
|
||||
in 200..299 -> if (isNight) { "11n" } else { "11d" }
|
||||
in 300..499 -> if (isNight) { "09n" } else { "09d" }
|
||||
in 500..509 -> if (isNight) { "10n" } else { "10d" }
|
||||
511 -> if (isNight) { "13n" } else { "13d" }
|
||||
in 512..599 -> if (isNight) { "09n" } else { "09d" }
|
||||
in 600..699 -> if (isNight) { "13n" } else { "13d" }
|
||||
in 700..799 -> if (isNight) { "50n" } else { "50d" }
|
||||
800 -> if (isNight) { "01n" } else { "01d" }
|
||||
801 -> if (isNight) { "02n" } else { "02d" }
|
||||
802 -> if (isNight) { "03n" } else { "03d" }
|
||||
803, 804 -> if (isNight) { "04n" } else { "04d" }
|
||||
else -> "02d" // fallback
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -149,10 +149,10 @@ class AppMessageHandlerObsidian extends AppMessageHandler {
|
||||
}
|
||||
|
||||
ArrayList<Pair<Integer, Object>> pairs = new ArrayList<>();
|
||||
boolean isNight = false; //TODO: use the night icons when night
|
||||
boolean isNight = weatherSpec.isNight();
|
||||
pairs.add(new Pair<>(messageKeys.get("CONFIG_WEATHER_REFRESH"), (Object) 60));
|
||||
pairs.add(new Pair<>(messageKeys.get("CONFIG_WEATHER_UNIT_LOCAL"), (Object) 1)); //celsius
|
||||
pairs.add(new Pair<>(messageKeys.get("MSG_KEY_WEATHER_ICON"), (Object) getIconForConditionCode(weatherSpec.getCurrentConditionCode(), isNight))); //celsius
|
||||
pairs.add(new Pair<>(messageKeys.get("MSG_KEY_WEATHER_ICON"), (Object) getIconForConditionCode(weatherSpec.getCurrentConditionCode(), isNight)));
|
||||
pairs.add(new Pair<>(messageKeys.get("MSG_KEY_WEATHER_TEMP"), (Object) (weatherSpec.getCurrentTemp() - 273)));
|
||||
|
||||
return mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs, null);
|
||||
@@ -173,4 +173,4 @@ class AppMessageHandlerObsidian extends AppMessageHandler {
|
||||
public byte[] encodeUpdateWeather(WeatherSpec weatherSpec) {
|
||||
return encodeObsidianWeather(weatherSpec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -115,7 +115,7 @@ class AppMessageHandlerRealWeather extends AppMessageHandler {
|
||||
if (weatherSpec == null) {
|
||||
return null;
|
||||
}
|
||||
boolean isNight = false; // TODO
|
||||
boolean isNight = weatherSpec.isNight();
|
||||
ArrayList<Pair<Integer, Object>> pairs = new ArrayList<>(2);
|
||||
pairs.add(new Pair<>(KEY_WEATHER_TEMP, (Object) (String.format(Locale.ENGLISH, "%.0f°", weatherSpec.getCurrentTemp() - 273.15))));
|
||||
pairs.add(new Pair<>(KEY_WEATHER_ICON, (Object) (getIconForConditionCode(weatherSpec.getCurrentConditionCode(), isNight))));
|
||||
|
||||
+1
-5
@@ -79,12 +79,8 @@ class AppMessageHandlerTearsOfTheKingdom extends AppMessageHandler {
|
||||
return null;
|
||||
}
|
||||
|
||||
int weather_time = weatherSpec.getTimestamp();
|
||||
// approximate night as the time as any time before sunrise or after sunset
|
||||
boolean isNight = ( weather_time < weatherSpec.getSunRise() ) || ( weather_time > weatherSpec.getSunSet()) ;
|
||||
|
||||
int temperature_f = (weatherSpec.getCurrentTemp() - 255) * 9 / 5; // 255K is 0 degF
|
||||
int condition = getIconFromConditionCode(weatherSpec.getCurrentConditionCode(), isNight);
|
||||
int condition = getIconFromConditionCode(weatherSpec.getCurrentConditionCode(), weatherSpec.isNight());
|
||||
|
||||
ArrayList<Pair<Integer, Object>> pairs = new ArrayList<>(2);
|
||||
pairs.add(new Pair<>(TEMPERATURE_KEY, (Object) temperature_f));
|
||||
|
||||
+1
-4
@@ -137,10 +137,7 @@ class AppMessageHandlerTimeStylePebble extends AppMessageHandler {
|
||||
|
||||
ArrayList<Pair<Integer, Object>> pairs = new ArrayList<>();
|
||||
|
||||
boolean isNight = false;
|
||||
if (weatherSpec.getSunRise() != 0 && weatherSpec.getSunSet() != 0) {
|
||||
isNight = weatherSpec.getSunRise() * 1000L > System.currentTimeMillis() || weatherSpec.getSunSet() * 1000L < System.currentTimeMillis();
|
||||
}
|
||||
boolean isNight = weatherSpec.isCurrentTimeNight();
|
||||
|
||||
pairs.add(new Pair<>(messageKeys.get("SettingUseMetric"), 1)); //celsius
|
||||
pairs.add(new Pair<>(messageKeys.get("WeatherUseNightIcon"), isNight ? 1 : 0));
|
||||
|
||||
+1
-1
@@ -190,7 +190,7 @@ class AppMessageHandlerYWeather extends AppMessageHandler {
|
||||
if (weatherSpec == null) {
|
||||
return null;
|
||||
}
|
||||
boolean isNight = false; // TODO
|
||||
boolean isNight = weatherSpec.isNight();
|
||||
ArrayList<Pair<Integer, Object>> pairs = new ArrayList<>(2);
|
||||
pairs.add(new Pair<>(KEY_LOCATION_NAME, (Object) (weatherSpec.getLocation())));
|
||||
pairs.add(new Pair<>(KEY_WEATHER_TEMP, (Object) (String.format(Locale.ENGLISH, "%.0f°", weatherSpec.getCurrentTemp() - 273.15))));
|
||||
|
||||
@@ -367,7 +367,7 @@ public class GBWebClient extends WebViewClient {
|
||||
condition.put("id", weatherSpec.getCurrentConditionCode());
|
||||
condition.put("main", weatherSpec.getCurrentCondition());
|
||||
condition.put("description", weatherSpec.getCurrentCondition());
|
||||
condition.put("icon", WeatherMapper.mapToOpenWeatherMapIcon(weatherSpec.getCurrentConditionCode()));
|
||||
condition.put("icon", WeatherMapper.mapToOpenWeatherMapIcon(weatherSpec.getCurrentConditionCode(),weatherSpec.isNight()));
|
||||
weather.put(condition);
|
||||
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ public class WeatherMapperTest extends TestBase {
|
||||
for (int i = 0; i <= 3200; i++) {
|
||||
Assert.assertEquals(Weather.mapToPebbleCondition(i), WeatherMapper.mapToPebbleCondition(i));
|
||||
Assert.assertEquals(Weather.mapToYahooCondition(i), WeatherMapper.mapToYahooCondition(i));
|
||||
Assert.assertEquals(Weather.mapToOpenWeatherMapIcon(i), WeatherMapper.mapToOpenWeatherMapIcon(i));
|
||||
Assert.assertEquals(Weather.mapToOpenWeatherMapIcon(i), WeatherMapper.mapToOpenWeatherMapIcon(i,false));
|
||||
Assert.assertEquals(Weather.mapToOpenWeatherMapCondition(i), WeatherMapper.mapToOpenWeatherMapCondition(i));
|
||||
Assert.assertEquals(Weather.getConditionString(getContext(), i), WeatherMapper.getConditionString(getContext(), i));
|
||||
Assert.assertEquals(Weather.getAqiLevelString(getContext(), i), WeatherMapper.getAqiLevelString(getContext(), i));
|
||||
|
||||
Reference in New Issue
Block a user