diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java index 4f5c69b5d..8aae5098f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java @@ -31,6 +31,8 @@ import android.companion.AssociationRequest; import android.companion.BluetoothDeviceFilter; import android.companion.CompanionDeviceManager; import android.content.BroadcastReceiver; +import android.content.ClipData; +import android.content.ClipboardManager; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; @@ -77,9 +79,11 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.io.Serializable; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; +import java.util.Date; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; @@ -361,7 +365,7 @@ public class DebugActivity extends AbstractGBActivity { weatherSpec.todayMaxTemp = 25 + 273; for (int i = 0; i < 5; i++) { - final WeatherSpec.Forecast gbForecast = new WeatherSpec.Forecast(); + final WeatherSpec.Daily gbForecast = new WeatherSpec.Daily(); gbForecast.minTemp = 10 + i + 273; gbForecast.maxTemp = 25 + i + 273; @@ -380,7 +384,7 @@ public class DebugActivity extends AbstractGBActivity { showCachedWeatherButton.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View v) { - String weatherInfo = getWeatherInfo(); + final String weatherInfo = getWeatherInfo(); new MaterialAlertDialogBuilder(DebugActivity.this) .setCancelable(true) @@ -388,6 +392,11 @@ public class DebugActivity extends AbstractGBActivity { .setMessage(weatherInfo) .setPositiveButton(R.string.ok, (dialog, which) -> { }) + .setNeutralButton(android.R.string.copy, (dialog, which) -> { + final ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clip = ClipData.newPlainText("Weather Info", weatherInfo); + clipboard.setPrimaryClip(clip); + }) .show(); } }); @@ -1032,34 +1041,110 @@ public class DebugActivity extends AbstractGBActivity { } private String getWeatherInfo() { - String info = ""; + final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.ROOT); + + final StringBuilder builder = new StringBuilder(); WeatherSpec weatherSpec = Weather.getInstance().getWeatherSpec(); if (weatherSpec == null) return "Weather cache is empty..."; - info += "Location: " + weatherSpec.location + "\n"; - info += "Timestamp: " + weatherSpec.timestamp + "\n"; - info += "Current Temp: " + weatherSpec.currentTemp + " K\n"; - info += "Max Temp: " + weatherSpec.todayMaxTemp + " K\n"; - info += "Min Temp: " + weatherSpec.todayMinTemp + " K\n"; - info += "Condition: " + weatherSpec.currentCondition + "\n"; - info += "Condition Code: " + weatherSpec.currentConditionCode + "\n"; - info += "Humidity: " + weatherSpec.currentHumidity + "\n"; - info += "Wind Speed: " + weatherSpec.windSpeed + " kmph\n"; - info += "Wind Direction: " + weatherSpec.windDirection + " deg\n"; - info += "UV Index: " + weatherSpec.uvIndex + "\n"; - info += "Precip Probability: " + weatherSpec.precipProbability + " %\n"; - for (int i=0;iDay ").append(i++).append("\n"); + builder.append("Max Temp: ").append(daily.maxTemp).append(" K\n"); + builder.append("Min Temp: ").append(daily.minTemp).append(" K\n"); + builder.append("Condition Code: ").append(daily.conditionCode).append("\n"); + builder.append("Humidity: ").append(daily.humidity).append("\n"); + builder.append("Wind Speed: ").append(daily.windSpeed).append(" kmph\n"); + builder.append("Wind Direction: ").append(daily.windDirection).append(" deg\n"); + builder.append("UV Index: ").append(daily.uvIndex).append("\n"); + builder.append("Precip Probability: ").append(daily.precipProbability).append(" %\n"); + builder.append("Sun Rise: ").append(sdf.format(new Date(daily.sunRise * 1000L))).append("\n"); + builder.append("Sun Set: ").append(sdf.format(new Date(daily.sunSet * 1000L))).append("\n"); + builder.append("Moon Rise: ").append(sdf.format(new Date(daily.moonRise * 1000L))).append("\n"); + builder.append("Moon Set: ").append(sdf.format(new Date(daily.moonSet * 1000L))).append("\n"); + builder.append("Moon Phase: ").append(daily.moonPhase).append(" deg\n"); + + if (daily.airQuality != null) { + builder.append("Air Quality aqi: ").append(daily.airQuality.aqi).append("\n"); + builder.append("Air Quality co: ").append(daily.airQuality.co).append("\n"); + builder.append("Air Quality no2: ").append(daily.airQuality.no2).append("\n"); + builder.append("Air Quality o3: ").append(daily.airQuality.o3).append("\n"); + builder.append("Air Quality pm10: ").append(daily.airQuality.pm10).append("\n"); + builder.append("Air Quality pm25: ").append(daily.airQuality.pm25).append("\n"); + builder.append("Air Quality so2: ").append(daily.airQuality.so2).append("\n"); + builder.append("Air Quality coAqi: ").append(daily.airQuality.coAqi).append("\n"); + builder.append("Air Quality no2Aqi: ").append(daily.airQuality.no2Aqi).append("\n"); + builder.append("Air Quality o3Aqi: ").append(daily.airQuality.o3Aqi).append("\n"); + builder.append("Air Quality pm10Aqi: ").append(daily.airQuality.pm10Aqi).append("\n"); + builder.append("Air Quality pm25Aqi: ").append(daily.airQuality.pm25Aqi).append("\n"); + builder.append("Air Quality so2Aqi: ").append(daily.airQuality.so2Aqi).append("\n"); + } else { + builder.append("Air Quality: null\n"); + } + } + + builder.append("=============\n"); + + for (final WeatherSpec.Hourly hourly : weatherSpec.hourly) { + builder.append("-------------\n"); + builder.append("-->Hour: ").append(sdf.format(new Date(hourly.timestamp * 1000L))).append("\n"); + builder.append("Max Temp: ").append(hourly.temp).append(" K\n"); + builder.append("Condition Code: ").append(hourly.conditionCode).append("\n"); + builder.append("Humidity: ").append(hourly.humidity).append("\n"); + builder.append("Wind Speed: ").append(hourly.windSpeed).append(" kmph\n"); + builder.append("Wind Direction: ").append(hourly.windDirection).append(" deg\n"); + builder.append("UV Index: ").append(hourly.uvIndex).append("\n"); + builder.append("Precip Probability: ").append(hourly.precipProbability).append(" %\n"); + } + + return builder.toString(); } public static LinkedHashMap getAllSupportedDevices(Context appContext) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/asteroidos/AsteroidOSWeather.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/asteroidos/AsteroidOSWeather.java index 5c1fc6949..06a9853c9 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/asteroidos/AsteroidOSWeather.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/asteroidos/AsteroidOSWeather.java @@ -32,7 +32,7 @@ public class AsteroidOSWeather { * Creates a Day from the forecast given * @param forecast */ - public Day(WeatherSpec.Forecast forecast) { + public Day(WeatherSpec.Daily forecast) { minTemp = forecast.minTemp; maxTemp = forecast.maxTemp; condition = forecast.conditionCode; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/smaq2oss/SMAQ2OSSSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/smaq2oss/SMAQ2OSSSupport.java index 77bba33f6..0dc5eecab 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/smaq2oss/SMAQ2OSSSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/smaq2oss/SMAQ2OSSSupport.java @@ -258,7 +258,7 @@ public class SMAQ2OSSSupport extends AbstractBTLEDeviceSupport { setWeather.setTemperatureMax(weatherSpec.todayMaxTemp-273); setWeather.setHumidity(weatherSpec.currentHumidity); - for (WeatherSpec.Forecast f:weatherSpec.forecasts) { + for (WeatherSpec.Daily f:weatherSpec.forecasts) { SMAQ2OSSProtos.Forecast.Builder fproto = SMAQ2OSSProtos.Forecast.newBuilder(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/CMWeatherReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/CMWeatherReceiver.java index 785456529..bd71fecc7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/CMWeatherReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/CMWeatherReceiver.java @@ -165,7 +165,7 @@ public class CMWeatherReceiver extends BroadcastReceiver implements CMWeatherMan List forecasts = weatherInfo.getForecasts(); for (int i = 1; i < forecasts.size(); i++) { WeatherInfo.DayForecast cmForecast = forecasts.get(i); - WeatherSpec.Forecast gbForecast = new WeatherSpec.Forecast(); + WeatherSpec.Daily gbForecast = new WeatherSpec.Daily(); if (weatherInfo.getTemperatureUnit() == FAHRENHEIT) { gbForecast.maxTemp = (int) WeatherUtils.fahrenheitToCelsius(cmForecast.getHigh()) + 273; gbForecast.minTemp = (int) WeatherUtils.fahrenheitToCelsius(cmForecast.getLow()) + 273; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/GenericWeatherReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/GenericWeatherReceiver.java index 28969d027..9e271f3a0 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/GenericWeatherReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/GenericWeatherReceiver.java @@ -63,6 +63,23 @@ public class GenericWeatherReceiver extends BroadcastReceiver { weatherSpec.windDirection = safelyGet(weatherJson, Integer.class, "windDirection", 0); weatherSpec.uvIndex = safelyGet(weatherJson, Number.class, "uvIndex", 0d).floatValue(); weatherSpec.precipProbability = safelyGet(weatherJson, Integer.class, "precipProbability", 0); + weatherSpec.dewPoint = safelyGet(weatherJson, Integer.class, "dewPoint", 0); + weatherSpec.pressure = safelyGet(weatherJson, Number.class, "pressure", 0).floatValue(); + weatherSpec.cloudCover = safelyGet(weatherJson, Integer.class, "cloudCover", 0); + weatherSpec.visibility = safelyGet(weatherJson, Number.class, "visibility", 0).floatValue(); + weatherSpec.sunRise = safelyGet(weatherJson, Integer.class, "sunRise", 0); + weatherSpec.sunSet = safelyGet(weatherJson, Integer.class, "sunSet", 0); + weatherSpec.moonRise = safelyGet(weatherJson, Integer.class, "moonRise", 0); + weatherSpec.moonSet = safelyGet(weatherJson, Integer.class, "moonSet", 0); + weatherSpec.moonPhase = safelyGet(weatherJson, Integer.class, "moonPhase", 0); + weatherSpec.latitude = safelyGet(weatherJson, Number.class, "latitude", 0).floatValue(); + weatherSpec.longitude = safelyGet(weatherJson, Number.class, "longitude", 0).floatValue(); + weatherSpec.feelsLikeTemp = safelyGet(weatherJson, Integer.class, "feelsLikeTemp", 0); + weatherSpec.isCurrentLocation = safelyGet(weatherJson, Integer.class, "isCurrentLocation", -1); + + if (weatherJson.has("airQuality")) { + weatherSpec.airQuality = toAirQuality(weatherJson.getJSONObject("airQuality")); + } if (weatherJson.has("forecasts")) { JSONArray forecastArray = weatherJson.getJSONArray("forecasts"); @@ -71,17 +88,52 @@ public class GenericWeatherReceiver extends BroadcastReceiver { for (int i = 0, l = forecastArray.length(); i < l; i++) { JSONObject forecastJson = forecastArray.getJSONObject(i); - WeatherSpec.Forecast forecast = new WeatherSpec.Forecast(); + WeatherSpec.Daily forecast = new WeatherSpec.Daily(); forecast.conditionCode = safelyGet(forecastJson, Integer.class, "conditionCode", 0); forecast.humidity = safelyGet(forecastJson, Integer.class, "humidity", 0); forecast.maxTemp = safelyGet(forecastJson, Integer.class, "maxTemp", 0); forecast.minTemp = safelyGet(forecastJson, Integer.class, "minTemp", 0); + forecast.windSpeed = safelyGet(forecastJson, Number.class, "windSpeed", 0).floatValue(); + forecast.windDirection = safelyGet(forecastJson, Integer.class, "windDirection", 0); + forecast.uvIndex = safelyGet(weatherJson, Number.class, "uvIndex", 0d).floatValue(); + forecast.precipProbability = safelyGet(weatherJson, Integer.class, "precipProbability", 0); + forecast.sunRise = safelyGet(forecastJson, Integer.class, "sunRise", 0); + forecast.sunSet = safelyGet(forecastJson, Integer.class, "sunSet", 0); + forecast.moonRise = safelyGet(forecastJson, Integer.class, "moonRise", 0); + forecast.moonSet = safelyGet(forecastJson, Integer.class, "moonSet", 0); + forecast.moonPhase = safelyGet(forecastJson, Integer.class, "moonPhase", 0); + + if (forecastJson.has("airQuality")) { + forecast.airQuality = toAirQuality(forecastJson.getJSONObject("airQuality")); + } weatherSpec.forecasts.add(forecast); } } + if (weatherJson.has("hourly")) { + JSONArray forecastArray = weatherJson.getJSONArray("hourly"); + weatherSpec.hourly = new ArrayList<>(); + + for (int i = 0, l = forecastArray.length(); i < l; i++) { + JSONObject forecastJson = forecastArray.getJSONObject(i); + + WeatherSpec.Hourly forecast = new WeatherSpec.Hourly(); + + forecast.timestamp = safelyGet(forecastJson, Integer.class, "timestamp", 0); + forecast.temp = safelyGet(forecastJson, Integer.class, "temp", 0); + forecast.conditionCode = safelyGet(forecastJson, Integer.class, "conditionCode", 0); + forecast.humidity = safelyGet(forecastJson, Integer.class, "humidity", 0); + forecast.windSpeed = safelyGet(forecastJson, Number.class, "windSpeed", 0).floatValue(); + forecast.windDirection = safelyGet(forecastJson, Integer.class, "windDirection", 0); + forecast.uvIndex = safelyGet(weatherJson, Number.class, "uvIndex", 0d).floatValue(); + forecast.precipProbability = safelyGet(weatherJson, Integer.class, "precipProbability", 0); + + weatherSpec.hourly.add(forecast); + } + } + LOG.info("Got generic weather for {}", weatherSpec.location); Weather.getInstance().setWeatherSpec(weatherSpec); @@ -93,6 +145,25 @@ public class GenericWeatherReceiver extends BroadcastReceiver { } } + private WeatherSpec.AirQuality toAirQuality(final JSONObject jsonObject) { + final WeatherSpec.AirQuality airQuality = new WeatherSpec.AirQuality(); + airQuality.aqi = safelyGet(jsonObject, Integer.class, "aqi", -1); + airQuality.co = safelyGet(jsonObject, Number.class, "co", -1).floatValue(); + airQuality.no2 = safelyGet(jsonObject, Number.class, "no2", -1).floatValue(); + airQuality.o3 = safelyGet(jsonObject, Number.class, "o3", -1).floatValue(); + airQuality.pm10 = safelyGet(jsonObject, Number.class, "pm10", -1).floatValue(); + airQuality.pm25 = safelyGet(jsonObject, Number.class, "pm25", -1).floatValue(); + airQuality.so2 = safelyGet(jsonObject, Number.class, "so2", -1).floatValue(); + airQuality.coAqi = safelyGet(jsonObject, Integer.class, "coAqi", -1); + airQuality.no2Aqi = safelyGet(jsonObject, Integer.class, "no2Aqi", -1); + airQuality.o3Aqi = safelyGet(jsonObject, Integer.class, "o3Aqi", -1); + airQuality.pm10Aqi = safelyGet(jsonObject, Integer.class, "pm10Aqi", -1); + airQuality.pm25Aqi = safelyGet(jsonObject, Integer.class, "pm25Aqi", -1); + airQuality.so2Aqi = safelyGet(jsonObject, Integer.class, "so2Aqi", -1); + + return airQuality; + } + private T safelyGet(JSONObject jsonObject, Class tClass, String name, T defaultValue) { try { if (jsonObject.has(name)) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/LineageOsWeatherReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/LineageOsWeatherReceiver.java index 6d5f0fefc..fc87df6a8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/LineageOsWeatherReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/LineageOsWeatherReceiver.java @@ -189,7 +189,7 @@ public class LineageOsWeatherReceiver extends BroadcastReceiver implements Linea List forecasts = weatherInfo.getForecasts(); for (int i = 1; i < forecasts.size(); i++) { WeatherInfo.DayForecast cmForecast = forecasts.get(i); - WeatherSpec.Forecast gbForecast = new WeatherSpec.Forecast(); + WeatherSpec.Daily gbForecast = new WeatherSpec.Daily(); if (weatherInfo.getTemperatureUnit() == FAHRENHEIT) { gbForecast.maxTemp = (int) WeatherUtils.fahrenheitToCelsius(cmForecast.getHigh()) + 273; gbForecast.minTemp = (int) WeatherUtils.fahrenheitToCelsius(cmForecast.getLow()) + 273; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/OmniJawsObserver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/OmniJawsObserver.java index 87fb07375..d59c34e61 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/OmniJawsObserver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/OmniJawsObserver.java @@ -127,7 +127,7 @@ public class OmniJawsObserver extends ContentObserver { weatherSpec.todayMaxTemp = toKelvin(c.getFloat(6)); } else { - WeatherSpec.Forecast gbForecast = new WeatherSpec.Forecast(); + WeatherSpec.Daily gbForecast = new WeatherSpec.Daily(); gbForecast.minTemp = toKelvin(c.getFloat(5)); gbForecast.maxTemp = toKelvin(c.getFloat(6)); gbForecast.conditionCode = Weather.mapToOpenWeatherMapCondition(c.getInt(8)); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/WeatherSpec.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/WeatherSpec.java index 6f2237284..26371c5f7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/WeatherSpec.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/WeatherSpec.java @@ -38,7 +38,7 @@ public class WeatherSpec implements Parcelable, Serializable { return new WeatherSpec[size]; } }; - public static final int VERSION = 3; + public static final int VERSION = 4; private static final long serialVersionUID = VERSION; public int timestamp; // unix epoch timestamp, in seconds public String location; @@ -52,10 +52,27 @@ public class WeatherSpec implements Parcelable, Serializable { public int windDirection; // deg public float uvIndex; public int precipProbability; // % + public int dewPoint; // kelvin + public float pressure; // mb + public int cloudCover; // % + public float visibility; // m + public int sunRise; // unix epoch timestamp, in seconds + public int sunSet; // unix epoch timestamp, in seconds + public int moonRise; // unix epoch timestamp, in seconds + public int moonSet; // unix epoch timestamp, in seconds + public int moonPhase; // deg + public float latitude; + public float longitude; + public int feelsLikeTemp; // kelvin + public int isCurrentLocation = -1; // 0 for false, 1 for true, -1 for unknown + public AirQuality airQuality; // Forecasts from the next day onward, in chronological order, one entry per day. // It should not include the current or previous days - public ArrayList forecasts = new ArrayList<>(); + public ArrayList forecasts = new ArrayList<>(); + + // Hourly forecasts + public ArrayList hourly = new ArrayList<>(); public WeatherSpec() { @@ -66,14 +83,18 @@ public class WeatherSpec implements Parcelable, Serializable { static final float[] beaufort = new float[] { 2, 6, 12, 20, 29, 39, 50, 62, 75, 89, 103, 118 }; // level: 0 1 2 3 4 5 6 7 8 9 10 11 12 - public int windSpeedAsBeaufort() { + public static int toBeaufort(final float speed) { int l = 0; - while (l < beaufort.length && beaufort[l] < this.windSpeed) { + while (l < beaufort.length && beaufort[l] < speed) { l++; } return l; } + public int windSpeedAsBeaufort() { + return toBeaufort(this.windSpeed); + } + protected WeatherSpec(Parcel in) { int version = in.readInt(); if (version >= 2) { @@ -87,12 +108,43 @@ public class WeatherSpec implements Parcelable, Serializable { todayMinTemp = in.readInt(); windSpeed = in.readFloat(); windDirection = in.readInt(); - in.readList(forecasts, Forecast.class.getClassLoader()); + if (version < 4) { + // Deserialize the old Forecast list and convert them to Daily + final ArrayList oldForecasts = new ArrayList<>(); + in.readList(oldForecasts, Forecast.class.getClassLoader()); + for (final Forecast forecast : oldForecasts) { + final Daily d = new Daily(); + d.minTemp = forecast.minTemp; + d.maxTemp = forecast.maxTemp; + d.conditionCode = forecast.conditionCode; + d.humidity = forecast.humidity; + forecasts.add(d); + } + } else { + in.readList(forecasts, Daily.class.getClassLoader()); + } } if (version >= 3) { uvIndex = in.readFloat(); precipProbability = in.readInt(); } + if (version >= 4) { + dewPoint = in.readInt(); + pressure = in.readFloat(); + cloudCover = in.readInt(); + visibility = in.readFloat(); + sunRise = in.readInt(); + sunSet = in.readInt(); + moonRise = in.readInt(); + moonSet = in.readInt(); + moonPhase = in.readInt(); + latitude = in.readFloat(); + longitude = in.readFloat(); + feelsLikeTemp = in.readInt(); + isCurrentLocation = in.readInt(); + airQuality = in.readParcelable(AirQuality.class.getClassLoader()); + in.readList(hourly, Hourly.class.getClassLoader()); + } } @Override @@ -116,8 +168,24 @@ public class WeatherSpec implements Parcelable, Serializable { dest.writeList(forecasts); dest.writeFloat(uvIndex); dest.writeInt(precipProbability); + dest.writeInt(dewPoint); + dest.writeFloat(pressure); + dest.writeInt(cloudCover); + dest.writeFloat(visibility); + dest.writeInt(sunRise); + dest.writeInt(sunSet); + dest.writeInt(moonRise); + dest.writeInt(moonSet); + dest.writeInt(moonPhase); + dest.writeFloat(latitude); + dest.writeFloat(longitude); + dest.writeInt(feelsLikeTemp); + dest.writeInt(isCurrentLocation); + dest.writeParcelable(airQuality, 0); + dest.writeList(hourly); } + @Deprecated // kept for backwards compatibility with old weather apps public static class Forecast implements Parcelable, Serializable { private static final long serialVersionUID = 1L; @@ -167,4 +235,221 @@ public class WeatherSpec implements Parcelable, Serializable { dest.writeInt(humidity); } } + + public static class AirQuality implements Parcelable, Serializable { + public static final int VERSION = 1; + private static final long serialVersionUID = VERSION; + + public static final Creator CREATOR = new Creator() { + @Override + public AirQuality createFromParcel(final Parcel in) { + return new AirQuality(in); + } + + @Override + public AirQuality[] newArray(final int size) { + return new AirQuality[size]; + } + }; + + public int aqi = -1; // plume AQI + public float co = -1; // mg/m^3 + public float no2 = -1; // ug/m^3 + public float o3 = -1; // ug/m^3 + public float pm10 = -1; // ug/m^3 + public float pm25 = -1; // ug/m^3 + public float so2 = -1; // ug/m^3 + public int coAqi = -1; + public int no2Aqi = -1; + public int o3Aqi = -1; + public int pm10Aqi = -1; + public int pm25Aqi = -1; + public int so2Aqi = -1; + + public AirQuality() { + } + + AirQuality(final Parcel in) { + in.readInt(); // version + aqi = in.readInt(); + co = in.readFloat(); + no2 = in.readFloat(); + o3 = in.readFloat(); + pm10 = in.readFloat(); + pm25 = in.readFloat(); + so2 = in.readFloat(); + coAqi = in.readInt(); + no2Aqi = in.readInt(); + o3Aqi = in.readInt(); + pm10Aqi = in.readInt(); + pm25Aqi = in.readInt(); + so2Aqi = in.readInt(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(final Parcel dest, final int flags) { + dest.writeInt(VERSION); + dest.writeInt(aqi); + dest.writeFloat(co); + dest.writeFloat(no2); + dest.writeFloat(o3); + dest.writeFloat(pm10); + dest.writeFloat(pm25); + dest.writeFloat(so2); + dest.writeInt(coAqi); + dest.writeInt(no2Aqi); + dest.writeInt(o3Aqi); + dest.writeInt(pm10Aqi); + dest.writeInt(pm25Aqi); + dest.writeInt(so2Aqi); + } + } + + public static class Daily implements Parcelable, Serializable { + public static final int VERSION = 1; + private static final long serialVersionUID = VERSION; + + public static final Creator CREATOR = new Creator() { + @Override + public Daily createFromParcel(final Parcel in) { + return new Daily(in); + } + + @Override + public Daily[] newArray(final int size) { + return new Daily[size]; + } + }; + public int minTemp; // Kelvin + public int maxTemp; // Kelvin + public int conditionCode; // OpenWeatherMap condition code + public int humidity; + public float windSpeed; // km per hour + public int windDirection; // deg + public float uvIndex; + public int precipProbability; // % + public int sunRise; + public int sunSet; + public int moonRise; + public int moonSet; + public int moonPhase; + public AirQuality airQuality; + + public Daily() { + } + + Daily(final Parcel in) { + in.readInt(); // version + minTemp = in.readInt(); + maxTemp = in.readInt(); + conditionCode = in.readInt(); + humidity = in.readInt(); + windSpeed = in.readFloat(); + windDirection = in.readInt(); + uvIndex = in.readFloat(); + precipProbability = in.readInt(); + sunRise = in.readInt(); + sunSet = in.readInt(); + moonRise = in.readInt(); + moonSet = in.readInt(); + moonPhase = in.readInt(); + airQuality = in.readParcelable(AirQuality.class.getClassLoader()); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(final Parcel dest, final int flags) { + dest.writeInt(VERSION); + dest.writeInt(minTemp); + dest.writeInt(maxTemp); + dest.writeInt(conditionCode); + dest.writeInt(humidity); + dest.writeFloat(windSpeed); + dest.writeInt(windDirection); + dest.writeFloat(uvIndex); + dest.writeInt(precipProbability); + dest.writeInt(sunRise); + dest.writeInt(sunSet); + dest.writeInt(moonRise); + dest.writeInt(moonSet); + dest.writeInt(moonPhase); + dest.writeParcelable(airQuality, 0); + } + + public int windSpeedAsBeaufort() { + return toBeaufort(this.windSpeed); + } + } + + public static class Hourly implements Parcelable, Serializable { + public static final int VERSION = 1; + private static final long serialVersionUID = VERSION; + + public static final Creator CREATOR = new Creator() { + @Override + public Hourly createFromParcel(final Parcel in) { + return new Hourly(in); + } + + @Override + public Hourly[] newArray(final int size) { + return new Hourly[size]; + } + }; + + public int timestamp; // unix epoch timestamp, in seconds + public int temp; // Kelvin + public int conditionCode; // OpenWeatherMap condition code + public int humidity; + public float windSpeed; // km per hour + public int windDirection; // deg + public float uvIndex; + public int precipProbability; // % + + public Hourly() { + } + + Hourly(final Parcel in) { + in.readInt(); // version + timestamp = in.readInt(); + temp = in.readInt(); + conditionCode = in.readInt(); + humidity = in.readInt(); + windSpeed = in.readFloat(); + windDirection = in.readInt(); + uvIndex = in.readFloat(); + precipProbability = in.readInt(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(final Parcel dest, final int flags) { + dest.writeInt(VERSION); + dest.writeInt(timestamp); + dest.writeInt(temp); + dest.writeInt(conditionCode); + dest.writeInt(humidity); + dest.writeFloat(windSpeed); + dest.writeInt(windDirection); + dest.writeFloat(uvIndex); + dest.writeInt(precipProbability); + } + + public int windSpeedAsBeaufort() { + return toBeaufort(this.windSpeed); + } + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/Huami2021Weather.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/Huami2021Weather.java index 7d30f45d6..773ffb1c1 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/Huami2021Weather.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/Huami2021Weather.java @@ -206,7 +206,7 @@ public class Huami2021Weather { windSpeed.add(new Range(0, 0)); for (int i = 0; i < actualDays; i++) { - final WeatherSpec.Forecast forecast = weatherSpec.forecasts.get(i); + final WeatherSpec.Daily forecast = weatherSpec.forecasts.get(i); temperature.add(new Range(forecast.minTemp - 273, forecast.maxTemp - 273)); final String weatherCode = String.valueOf(mapToZeppOsWeatherCode(forecast.conditionCode)); weather.add(new Range(weatherCode, weatherCode)); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java index 0985b63f2..916ffa042 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java @@ -3192,7 +3192,7 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport implements if (supportsConditionString) { bytesPerDay = 5; conditionsLength = weatherSpec.currentCondition.getBytes().length; - for (WeatherSpec.Forecast forecast : weatherSpec.forecasts) { + for (WeatherSpec.Daily forecast : weatherSpec.forecasts) { conditionsLength += Weather.getConditionString(forecast.conditionCode).getBytes().length; } } @@ -3225,7 +3225,7 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport implements buf.put((byte) 0); } - for (WeatherSpec.Forecast forecast : weatherSpec.forecasts) { + for (WeatherSpec.Daily forecast : weatherSpec.forecasts) { condition = HuamiWeatherConditions.mapToAmazfitBipWeatherCode(forecast.conditionCode); buf.put(condition); buf.put(condition); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsAlexaService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsAlexaService.java index a1f632f84..d82464206 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsAlexaService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsAlexaService.java @@ -234,7 +234,7 @@ public class ZeppOsAlexaService extends AbstractZeppOsService { // FIXME baos.write(weather.forecasts.size()); - for (final WeatherSpec.Forecast forecast : weather.forecasts) { + for (final WeatherSpec.Daily forecast : weather.forecasts) { // FIXME } } catch (final IOException e) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java index 048c7f8f9..f3a4c07e0 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java @@ -143,7 +143,7 @@ class AppMessageHandlerTimeStylePebble extends AppMessageHandler { pairs.add(new Pair<>(messageKeys.get("WeatherCondition"), (Object) (getIconForConditionCode(weatherSpec.currentConditionCode, isNight)))); if (weatherSpec.forecasts.size() > 0) { - WeatherSpec.Forecast tomorrow = weatherSpec.forecasts.get(0); + WeatherSpec.Daily tomorrow = weatherSpec.forecasts.get(0); pairs.add(new Pair<>(messageKeys.get("WeatherForecastCondition"), (Object) (getIconForConditionCode(tomorrow.conditionCode, isNight)))); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerYWeather.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerYWeather.java index d4976fc7f..40d987d3c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerYWeather.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerYWeather.java @@ -200,19 +200,19 @@ class AppMessageHandlerYWeather extends AppMessageHandler { pairs.add(new Pair<>(KEY_WEATHER_WIND_SPEED, (Object) (String.format(Locale.ENGLISH, "%.0f", weatherSpec.windSpeed)))); pairs.add(new Pair<>(KEY_WEATHER_WIND_DIRECTION, (Object) (formatWindDirection(weatherSpec.windDirection)))); if (weatherSpec.forecasts.size() > 0) { - WeatherSpec.Forecast day1 = weatherSpec.forecasts.get(0); + WeatherSpec.Daily day1 = weatherSpec.forecasts.get(0); pairs.add(new Pair<>(KEY_WEATHER_D1_ICON, (Object) (getIconForConditionCode(day1.conditionCode, false)))); pairs.add(new Pair<>(KEY_WEATHER_D1_MINTEMP, (Object) (String.format(Locale.ENGLISH, "%.0f°C", day1.minTemp - 273.15)))); pairs.add(new Pair<>(KEY_WEATHER_D1_MAXTEMP, (Object) (String.format(Locale.ENGLISH, "%.0f°C", day1.maxTemp - 273.15)))); } if (weatherSpec.forecasts.size() > 1) { - WeatherSpec.Forecast day2 = weatherSpec.forecasts.get(1); + WeatherSpec.Daily day2 = weatherSpec.forecasts.get(1); pairs.add(new Pair<>(KEY_WEATHER_D2_ICON, (Object) (getIconForConditionCode(day2.conditionCode, false)))); pairs.add(new Pair<>(KEY_WEATHER_D2_MINTEMP, (Object) (String.format(Locale.ENGLISH, "%.0f°C", day2.minTemp - 273.15)))); pairs.add(new Pair<>(KEY_WEATHER_D2_MAXTEMP, (Object) (String.format(Locale.ENGLISH, "%.0f°C", day2.maxTemp - 273.15)))); } if (weatherSpec.forecasts.size() > 2) { - WeatherSpec.Forecast day3 = weatherSpec.forecasts.get(2); + WeatherSpec.Daily day3 = weatherSpec.forecasts.get(2); pairs.add(new Pair<>(KEY_WEATHER_D3_ICON, (Object) (getIconForConditionCode(day3.conditionCode, false)))); pairs.add(new Pair<>(KEY_WEATHER_D3_MINTEMP, (Object) (String.format(Locale.ENGLISH, "%.0f°C", day3.minTemp - 273.15)))); pairs.add(new Pair<>(KEY_WEATHER_D3_MAXTEMP, (Object) (String.format(Locale.ENGLISH, "%.0f°C", day3.maxTemp - 273.15)))); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 24cc2a12c..64bb7e68a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -1142,7 +1142,7 @@ public class PebbleProtocol extends GBDeviceProtocol { short tomorrowMin = 0; int tomorrowConditionCode = 0; if (weatherSpec.forecasts.size() > 0) { - WeatherSpec.Forecast tomorrow = weatherSpec.forecasts.get(0); + WeatherSpec.Daily tomorrow = weatherSpec.forecasts.get(0); tomorrowMax = (short) (tomorrow.maxTemp - 273); tomorrowMin = (short) (tomorrow.minTemp - 273); tomorrowConditionCode = tomorrow.conditionCode; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java index a55f6f68d..173103820 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java @@ -1471,7 +1471,7 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(weatherSpec.timestamp * 1000L); int i = 0; - for (WeatherSpec.Forecast forecast : weatherSpec.forecasts) { + for (WeatherSpec.Daily forecast : weatherSpec.forecasts) { cal.add(Calendar.DATE, 1); int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); forecastWeekArray.put(new JSONObject() diff --git a/app/src/main/java/ru/gelin/android/weather/notification/ParcelableWeather2.java b/app/src/main/java/ru/gelin/android/weather/notification/ParcelableWeather2.java index ce8628147..b75574ab8 100644 --- a/app/src/main/java/ru/gelin/android/weather/notification/ParcelableWeather2.java +++ b/app/src/main/java/ru/gelin/android/weather/notification/ParcelableWeather2.java @@ -89,7 +89,12 @@ public class ParcelableWeather2 implements Parcelable { int forecastLowTemp = forecastBundle.getInt("weather_low_temp"); int forecastHighTemp = forecastBundle.getInt("weather_high_temp"); int forecastHumidity = forecastBundle.getInt("weather_humidity_value"); - weatherSpec.forecasts.add(new WeatherSpec.Forecast(forecastLowTemp, forecastHighTemp, forecastConditionCode, forecastHumidity)); + WeatherSpec.Daily daily = new WeatherSpec.Daily(); + daily.minTemp = forecastLowTemp; + daily.maxTemp = forecastHighTemp; + daily.conditionCode = forecastConditionCode; + daily.humidity = forecastHumidity; + weatherSpec.forecasts.add(daily); try { condition.put("id", forecastConditionCode); condition.put("main", forecastBundle.getString("weather_condition_text"));