mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-09-06 06:25:20 +02:00
482 lines
16 KiB
Java
482 lines
16 KiB
Java
/* Copyright (C) 2016-2024 Andreas Shimokawa, Arjan Schrijver, beardhatcode,
|
|
Carsten Pfeiffer, Daniele Gobbetti, Enrico Brambilla, José Rebelo, Taavi
|
|
Eomäe
|
|
|
|
This file is part of Gadgetbridge.
|
|
|
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as published
|
|
by the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Gadgetbridge is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|
|
|
package nodomain.freeyourgadget.gadgetbridge.model;
|
|
|
|
import android.location.Location;
|
|
import android.os.Parcel;
|
|
import android.os.Parcelable;
|
|
|
|
import androidx.annotation.Nullable;
|
|
|
|
import java.io.Serializable;
|
|
import java.util.ArrayList;
|
|
|
|
// FIXME: document me and my fields, including units
|
|
public class WeatherSpec implements Parcelable, Serializable {
|
|
|
|
public static final Creator<WeatherSpec> CREATOR = new Creator<WeatherSpec>() {
|
|
@Override
|
|
public WeatherSpec createFromParcel(Parcel in) {
|
|
return new WeatherSpec(in);
|
|
}
|
|
|
|
@Override
|
|
public WeatherSpec[] newArray(int size) {
|
|
return new WeatherSpec[size];
|
|
}
|
|
};
|
|
public static final int VERSION = 4;
|
|
private static final long serialVersionUID = VERSION;
|
|
public int timestamp; // unix epoch timestamp, in seconds
|
|
public String location;
|
|
public int currentTemp; // kelvin
|
|
public int currentConditionCode = 3200; // OpenWeatherMap condition code
|
|
public String currentCondition;
|
|
public int currentHumidity;
|
|
public int todayMaxTemp; // kelvin
|
|
public int todayMinTemp; // kelvin
|
|
public float windSpeed; // km per hour
|
|
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<Daily> forecasts = new ArrayList<>();
|
|
|
|
// Hourly forecasts
|
|
public ArrayList<Hourly> hourly = new ArrayList<>();
|
|
|
|
public WeatherSpec() {
|
|
|
|
}
|
|
|
|
// Lower bounds of beaufort regions 1 to 12
|
|
// Values from https://en.wikipedia.org/wiki/Beaufort_scale
|
|
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 static int toBeaufort(final float speed) {
|
|
int l = 0;
|
|
while (l < beaufort.length && beaufort[l] < speed) {
|
|
l++;
|
|
}
|
|
return l;
|
|
}
|
|
|
|
public int windSpeedAsBeaufort() {
|
|
return toBeaufort(this.windSpeed);
|
|
}
|
|
|
|
@Nullable
|
|
public Location getLocation() {
|
|
if (latitude == 0 && longitude == 0) {
|
|
return null;
|
|
}
|
|
final Location location = new Location("weatherSpec");
|
|
location.setLatitude(latitude);
|
|
location.setLongitude(longitude);
|
|
return location;
|
|
}
|
|
|
|
protected WeatherSpec(Parcel in) {
|
|
int version = in.readInt();
|
|
if (version >= 2) {
|
|
timestamp = in.readInt();
|
|
location = in.readString();
|
|
currentTemp = in.readInt();
|
|
currentConditionCode = in.readInt();
|
|
currentCondition = in.readString();
|
|
currentHumidity = in.readInt();
|
|
todayMaxTemp = in.readInt();
|
|
todayMinTemp = in.readInt();
|
|
windSpeed = in.readFloat();
|
|
windDirection = in.readInt();
|
|
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
|
|
public int describeContents() {
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
public void writeToParcel(Parcel dest, int flags) {
|
|
dest.writeInt(VERSION);
|
|
dest.writeInt(timestamp);
|
|
dest.writeString(location);
|
|
dest.writeInt(currentTemp);
|
|
dest.writeInt(currentConditionCode);
|
|
dest.writeString(currentCondition);
|
|
dest.writeInt(currentHumidity);
|
|
dest.writeInt(todayMaxTemp);
|
|
dest.writeInt(todayMinTemp);
|
|
dest.writeFloat(windSpeed);
|
|
dest.writeInt(windDirection);
|
|
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;
|
|
|
|
public static final Creator<Forecast> CREATOR = new Creator<Forecast>() {
|
|
@Override
|
|
public Forecast createFromParcel(Parcel in) {
|
|
return new Forecast(in);
|
|
}
|
|
|
|
@Override
|
|
public Forecast[] newArray(int size) {
|
|
return new Forecast[size];
|
|
}
|
|
};
|
|
public int minTemp; // Kelvin
|
|
public int maxTemp; // Kelvin
|
|
public int conditionCode; // OpenWeatherMap condition code
|
|
public int humidity;
|
|
|
|
public Forecast() {
|
|
}
|
|
|
|
public Forecast(int minTemp, int maxTemp, int conditionCode, int humidity) {
|
|
this.minTemp = minTemp;
|
|
this.maxTemp = maxTemp;
|
|
this.conditionCode = conditionCode;
|
|
this.humidity = humidity;
|
|
}
|
|
|
|
Forecast(Parcel in) {
|
|
minTemp = in.readInt();
|
|
maxTemp = in.readInt();
|
|
conditionCode = in.readInt();
|
|
humidity = in.readInt();
|
|
}
|
|
|
|
@Override
|
|
public int describeContents() {
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
public void writeToParcel(Parcel dest, int flags) {
|
|
dest.writeInt(minTemp);
|
|
dest.writeInt(maxTemp);
|
|
dest.writeInt(conditionCode);
|
|
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; // Air Quality Index - usually the max across all AQI values for pollutants
|
|
|
|
public float co = -1; // Carbon Monoxide, mg/m^3
|
|
public float no2 = -1; // Nitrogen Dioxide, ug/m^3
|
|
public float o3 = -1; // Ozone, ug/m^3
|
|
public float pm10 = -1; // Particulate Matter, 10 microns or less in diameter, ug/m^3
|
|
public float pm25 = -1; // Particulate Matter, 2.5 microns or less in diameter, ug/m^3
|
|
public float so2 = -1; // Sulphur Dioxide, ug/m^3
|
|
|
|
// Air Quality Index values per pollutant
|
|
// These are expected to be in the Plume scale (see https://plumelabs.files.wordpress.com/2023/06/plume_aqi_2023.pdf)
|
|
// Some apps such as Breezy Weather fallback to the WHO 2021 AQI for pollutants that are not mapped in the Plume AQI
|
|
// https://www.who.int/news-room/fact-sheets/detail/ambient-(outdoor)-air-quality-and-health
|
|
//
|
|
// Breezy Weather implementation for reference:
|
|
// - https://github.com/breezy-weather/breezy-weather/blob/main/app/src/main/java/org/breezyweather/common/basic/models/weather/AirQuality.kt
|
|
// - https://github.com/breezy-weather/breezy-weather/blob/main/app/src/main/java/org/breezyweather/common/basic/models/options/index/PollutantIndex.kt
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|