1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-25 11:26:47 +01:00

Introduce WeatherSpec v4

New fields for current weather:

- dewPoint
- pressure
- cloudCover
- visibility
- sunRise
- sunSet
- moonRise
- moonSet
- moonPhase
- airQuality
- latitude
- longitude
- feelsLikeTemp
- isCurrentLocation

New fields for daily forecast:

Deprecate the old "Forecast" class, which was not versioned, but keep it for backwards compatibility with old apps. Old WeatherSpec forecasts are de-serialized into the new Daily class. New fields:

- windSpeed
- windDirection
- uvIndex
- precipProbability
- sunRise
- sunSet
- moonRise
- moonSet
- moonPhase
- airQuality

Add hourly values:
- timestamp
- temp
- conditionCode
- humidity
- windSpeed
- windDirection
- uvIndex
- precipProbability

Air Quality:
- aqi (plume)
- co
- no2
- o3
- pm10
- pm25
- so2
- coAqi
- no2Aqi
- o3Aqi
- pm10Aqi
- pm25Aqi
- so2Aqi
This commit is contained in:
José Rebelo 2023-08-25 22:32:17 +01:00 committed by José Rebelo
parent b7e6a39ec1
commit 564cb1bfcc
16 changed files with 491 additions and 45 deletions

View File

@ -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;i<weatherSpec.forecasts.size();i++) {
info += "-------------\n";
info += "-->Day " + i +"\n";
info += "Max Temp: " + weatherSpec.forecasts.get(i).maxTemp + " K\n";
info += "Min Temp: " + weatherSpec.forecasts.get(i).minTemp + " K\n";
info += "Condition Code: " + weatherSpec.forecasts.get(i).conditionCode + "\n";
info += "Humidity: " + weatherSpec.forecasts.get(i).humidity + "\n";
builder.append("Location: ").append(weatherSpec.location).append("\n");
builder.append("Timestamp: ").append(weatherSpec.timestamp).append("\n");
builder.append("Current Temp: ").append(weatherSpec.currentTemp).append(" K\n");
builder.append("Max Temp: ").append(weatherSpec.todayMaxTemp).append(" K\n");
builder.append("Min Temp: ").append(weatherSpec.todayMinTemp).append(" K\n");
builder.append("Condition: ").append(weatherSpec.currentCondition).append("\n");
builder.append("Condition Code: ").append(weatherSpec.currentConditionCode).append("\n");
builder.append("Humidity: ").append(weatherSpec.currentHumidity).append("\n");
builder.append("Wind Speed: ").append(weatherSpec.windSpeed).append(" kmph\n");
builder.append("Wind Direction: ").append(weatherSpec.windDirection).append(" deg\n");
builder.append("UV Index: ").append(weatherSpec.uvIndex).append("\n");
builder.append("Precip Probability: ").append(weatherSpec.precipProbability).append(" %\n");
builder.append("Dew Point: ").append(weatherSpec.dewPoint).append(" K\n");
builder.append("Pressure: ").append(weatherSpec.pressure).append(" mb\n");
builder.append("Cloud Cover: ").append(weatherSpec.cloudCover).append(" %\n");
builder.append("Visibility: ").append(weatherSpec.visibility).append(" m\n");
builder.append("Sun Rise: ").append(sdf.format(new Date(weatherSpec.sunRise * 1000L))).append("\n");
builder.append("Sun Set: ").append(sdf.format(new Date(weatherSpec.sunSet * 1000L))).append("\n");
builder.append("Moon Rise: ").append(sdf.format(new Date(weatherSpec.moonRise * 1000L))).append("\n");
builder.append("Moon Set: ").append(sdf.format(new Date(weatherSpec.moonSet * 1000L))).append("\n");
builder.append("Moon Phase: ").append(weatherSpec.moonPhase).append(" deg\n");
builder.append("Latitude: ").append(weatherSpec.latitude).append("\n");
builder.append("Longitude: ").append(weatherSpec.longitude).append("\n");
builder.append("Feels Like Temp: ").append(weatherSpec.feelsLikeTemp).append(" K\n");
builder.append("Is Current Location: ").append(weatherSpec.isCurrentLocation).append("\n");
if (weatherSpec.airQuality != null) {
builder.append("Air Quality aqi: ").append(weatherSpec.airQuality.aqi).append("\n");
builder.append("Air Quality co: ").append(weatherSpec.airQuality.co).append("\n");
builder.append("Air Quality no2: ").append(weatherSpec.airQuality.no2).append("\n");
builder.append("Air Quality o3: ").append(weatherSpec.airQuality.o3).append("\n");
builder.append("Air Quality pm10: ").append(weatherSpec.airQuality.pm10).append("\n");
builder.append("Air Quality pm25: ").append(weatherSpec.airQuality.pm25).append("\n");
builder.append("Air Quality so2: ").append(weatherSpec.airQuality.so2).append("\n");
builder.append("Air Quality coAqi: ").append(weatherSpec.airQuality.coAqi).append("\n");
builder.append("Air Quality no2Aqi: ").append(weatherSpec.airQuality.no2Aqi).append("\n");
builder.append("Air Quality o3Aqi: ").append(weatherSpec.airQuality.o3Aqi).append("\n");
builder.append("Air Quality pm10Aqi: ").append(weatherSpec.airQuality.pm10Aqi).append("\n");
builder.append("Air Quality pm25Aqi: ").append(weatherSpec.airQuality.pm25Aqi).append("\n");
builder.append("Air Quality so2Aqi: ").append(weatherSpec.airQuality.so2Aqi).append("\n");
} else {
builder.append("Air Quality: null\n");
}
return info;
int i = 0;
for (final WeatherSpec.Daily daily : weatherSpec.forecasts) {
builder.append("-------------\n");
builder.append("-->Day ").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) {

View File

@ -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;

View File

@ -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();

View File

@ -165,7 +165,7 @@ public class CMWeatherReceiver extends BroadcastReceiver implements CMWeatherMan
List<WeatherInfo.DayForecast> 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;

View File

@ -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> T safelyGet(JSONObject jsonObject, Class<T> tClass, String name, T defaultValue) {
try {
if (jsonObject.has(name)) {

View File

@ -189,7 +189,7 @@ public class LineageOsWeatherReceiver extends BroadcastReceiver implements Linea
List<WeatherInfo.DayForecast> 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;

View File

@ -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));

View File

@ -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<Forecast> forecasts = new ArrayList<>();
public ArrayList<Daily> forecasts = new ArrayList<>();
// Hourly forecasts
public ArrayList<Hourly> 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<Forecast> 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<AirQuality> CREATOR = new Creator<AirQuality>() {
@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<Daily> CREATOR = new Creator<Daily>() {
@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<Hourly> CREATOR = new Creator<Hourly>() {
@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);
}
}
}

View File

@ -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));

View File

@ -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);

View File

@ -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) {

View File

@ -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))));
}

View File

@ -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))));

View File

@ -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;

View File

@ -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()

View File

@ -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"));