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:
parent
b7e6a39ec1
commit
564cb1bfcc
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)) {
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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))));
|
||||
}
|
||||
|
||||
|
@ -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))));
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
|
@ -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"));
|
||||
|
Loading…
Reference in New Issue
Block a user