mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-12-01 06:22:55 +01:00
Garmin: improve weather information
Add Aqi Field Definition and field to today weather and daily forecast, as both are available in WeatherSpec. Add Feels like temperature to hourly forecast but populate with the forecasted temperature as the field is not available in Weatherspec for hourly. Use temperature Field Definition for dew point and add it to today's weather. Fields dew point and air quality could have been removed from the hourly weather definition but are kept in to test compatibility of these changes with watches.
This commit is contained in:
parent
ebe371de3c
commit
2a9a01e40b
@ -369,6 +369,10 @@ public class GarminSupport extends AbstractBTLEDeviceSupport implements ICommuni
|
|||||||
today.setFieldByName("relative_humidity", weather.currentHumidity);
|
today.setFieldByName("relative_humidity", weather.currentHumidity);
|
||||||
today.setFieldByName("observed_location_lat", weather.latitude);
|
today.setFieldByName("observed_location_lat", weather.latitude);
|
||||||
today.setFieldByName("observed_location_long", weather.longitude);
|
today.setFieldByName("observed_location_long", weather.longitude);
|
||||||
|
today.setFieldByName("dew_point", weather.dewPoint);
|
||||||
|
if (null != weather.airQuality) {
|
||||||
|
today.setFieldByName("air_quality", weather.airQuality.aqi);
|
||||||
|
}
|
||||||
today.setFieldByName("location", weather.location);
|
today.setFieldByName("location", weather.location);
|
||||||
weatherData.add(today);
|
weatherData.add(today);
|
||||||
|
|
||||||
@ -380,13 +384,14 @@ public class GarminSupport extends AbstractBTLEDeviceSupport implements ICommuni
|
|||||||
weatherHourlyForecast.setFieldByName("timestamp", hourly.timestamp);
|
weatherHourlyForecast.setFieldByName("timestamp", hourly.timestamp);
|
||||||
weatherHourlyForecast.setFieldByName("temperature", hourly.temp);
|
weatherHourlyForecast.setFieldByName("temperature", hourly.temp);
|
||||||
weatherHourlyForecast.setFieldByName("condition", hourly.conditionCode);
|
weatherHourlyForecast.setFieldByName("condition", hourly.conditionCode);
|
||||||
|
weatherHourlyForecast.setFieldByName("temperature_feels_like", hourly.temp); //TODO: switch to actual feels like field once Hourly contains this information
|
||||||
weatherHourlyForecast.setFieldByName("wind_direction", hourly.windDirection);
|
weatherHourlyForecast.setFieldByName("wind_direction", hourly.windDirection);
|
||||||
weatherHourlyForecast.setFieldByName("wind_speed", Math.round(hourly.windSpeed));
|
weatherHourlyForecast.setFieldByName("wind_speed", Math.round(hourly.windSpeed));
|
||||||
weatherHourlyForecast.setFieldByName("precipitation_probability", hourly.precipProbability);
|
weatherHourlyForecast.setFieldByName("precipitation_probability", hourly.precipProbability);
|
||||||
weatherHourlyForecast.setFieldByName("relative_humidity", hourly.humidity);
|
weatherHourlyForecast.setFieldByName("relative_humidity", hourly.humidity);
|
||||||
// weatherHourlyForecast.setFieldByName("dew_point", 0); // dew_point sint8
|
// weatherHourlyForecast.setFieldByName("dew_point", 0); // TODO: add once Hourly contains this information
|
||||||
weatherHourlyForecast.setFieldByName("uv_index", hourly.uvIndex);
|
weatherHourlyForecast.setFieldByName("uv_index", hourly.uvIndex);
|
||||||
// weatherHourlyForecast.setFieldByName("air_quality", 0); // air_quality enum
|
// weatherHourlyForecast.setFieldByName("air_quality", 0); // TODO: add once Hourly contains this information
|
||||||
weatherData.add(weatherHourlyForecast);
|
weatherData.add(weatherHourlyForecast);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -399,6 +404,9 @@ public class GarminSupport extends AbstractBTLEDeviceSupport implements ICommuni
|
|||||||
todayDailyForecast.setFieldByName("condition", weather.currentConditionCode);
|
todayDailyForecast.setFieldByName("condition", weather.currentConditionCode);
|
||||||
todayDailyForecast.setFieldByName("precipitation_probability", weather.precipProbability);
|
todayDailyForecast.setFieldByName("precipitation_probability", weather.precipProbability);
|
||||||
todayDailyForecast.setFieldByName("day_of_week", weather.timestamp);
|
todayDailyForecast.setFieldByName("day_of_week", weather.timestamp);
|
||||||
|
if (null != weather.airQuality) {
|
||||||
|
todayDailyForecast.setFieldByName("air_quality", weather.airQuality.aqi);
|
||||||
|
}
|
||||||
weatherData.add(todayDailyForecast);
|
weatherData.add(todayDailyForecast);
|
||||||
|
|
||||||
|
|
||||||
@ -413,6 +421,9 @@ public class GarminSupport extends AbstractBTLEDeviceSupport implements ICommuni
|
|||||||
weatherDailyForecast.setFieldByName("high_temperature", daily.maxTemp);
|
weatherDailyForecast.setFieldByName("high_temperature", daily.maxTemp);
|
||||||
weatherDailyForecast.setFieldByName("condition", daily.conditionCode);
|
weatherDailyForecast.setFieldByName("condition", daily.conditionCode);
|
||||||
weatherDailyForecast.setFieldByName("precipitation_probability", daily.precipProbability);
|
weatherDailyForecast.setFieldByName("precipitation_probability", daily.precipProbability);
|
||||||
|
if (null != daily.airQuality) {
|
||||||
|
weatherDailyForecast.setFieldByName("air_quality", daily.airQuality.aqi);
|
||||||
|
}
|
||||||
weatherDailyForecast.setFieldByName("day_of_week", ts);
|
weatherDailyForecast.setFieldByName("day_of_week", ts);
|
||||||
weatherData.add(weatherDailyForecast);
|
weatherData.add(weatherDailyForecast);
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefi
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionSleepStage;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionSleepStage;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionTemperature;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionTemperature;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionTimestamp;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionTimestamp;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionWeatherAqi;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionWeatherCondition;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionWeatherCondition;
|
||||||
|
|
||||||
public class FieldDefinitionFactory {
|
public class FieldDefinitionFactory {
|
||||||
@ -41,6 +42,8 @@ public class FieldDefinitionFactory {
|
|||||||
return new FieldDefinitionLanguage(localNumber, size, baseType, name);
|
return new FieldDefinitionLanguage(localNumber, size, baseType, name);
|
||||||
case SLEEP_STAGE:
|
case SLEEP_STAGE:
|
||||||
return new FieldDefinitionSleepStage(localNumber, size, baseType, name);
|
return new FieldDefinitionSleepStage(localNumber, size, baseType, name);
|
||||||
|
case WEATHER_AQI:
|
||||||
|
return new FieldDefinitionWeatherAqi(localNumber, size, baseType, name);
|
||||||
default:
|
default:
|
||||||
return new FieldDefinition(localNumber, size, baseType, name);
|
return new FieldDefinition(localNumber, size, baseType, name);
|
||||||
}
|
}
|
||||||
@ -58,5 +61,6 @@ public class FieldDefinitionFactory {
|
|||||||
WEATHER_CONDITION,
|
WEATHER_CONDITION,
|
||||||
LANGUAGE,
|
LANGUAGE,
|
||||||
SLEEP_STAGE,
|
SLEEP_STAGE,
|
||||||
|
WEATHER_AQI,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,9 +183,9 @@ public class GlobalFITMessage {
|
|||||||
new FieldDefinitionPrimitive(12, BaseType.ENUM, "day_of_week", FieldDefinitionFactory.FIELD.DAY_OF_WEEK),
|
new FieldDefinitionPrimitive(12, BaseType.ENUM, "day_of_week", FieldDefinitionFactory.FIELD.DAY_OF_WEEK),
|
||||||
new FieldDefinitionPrimitive(13, BaseType.SINT8, "high_temperature", FieldDefinitionFactory.FIELD.TEMPERATURE),
|
new FieldDefinitionPrimitive(13, BaseType.SINT8, "high_temperature", FieldDefinitionFactory.FIELD.TEMPERATURE),
|
||||||
new FieldDefinitionPrimitive(14, BaseType.SINT8, "low_temperature", FieldDefinitionFactory.FIELD.TEMPERATURE),
|
new FieldDefinitionPrimitive(14, BaseType.SINT8, "low_temperature", FieldDefinitionFactory.FIELD.TEMPERATURE),
|
||||||
new FieldDefinitionPrimitive(15, BaseType.SINT8, "dew_point"),
|
new FieldDefinitionPrimitive(15, BaseType.SINT8, "dew_point", FieldDefinitionFactory.FIELD.TEMPERATURE),
|
||||||
new FieldDefinitionPrimitive(16, BaseType.FLOAT32, "uv_index"),
|
new FieldDefinitionPrimitive(16, BaseType.FLOAT32, "uv_index"),
|
||||||
new FieldDefinitionPrimitive(17, BaseType.ENUM, "air_quality"),
|
new FieldDefinitionPrimitive(17, BaseType.ENUM, "air_quality", FieldDefinitionFactory.FIELD.WEATHER_AQI),
|
||||||
new FieldDefinitionPrimitive(253, BaseType.UINT32, "timestamp", FieldDefinitionFactory.FIELD.TIMESTAMP)
|
new FieldDefinitionPrimitive(253, BaseType.UINT32, "timestamp", FieldDefinitionFactory.FIELD.TIMESTAMP)
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -7,13 +7,13 @@ import java.util.List;
|
|||||||
|
|
||||||
public enum PredefinedLocalMessage {
|
public enum PredefinedLocalMessage {
|
||||||
TODAY_WEATHER_CONDITIONS(6, GlobalFITMessage.WEATHER,
|
TODAY_WEATHER_CONDITIONS(6, GlobalFITMessage.WEATHER,
|
||||||
new int[]{0, 253, 9, 1, 14, 13, 2, 3, 5, 4, 6, 7, 10, 11, 8}
|
new int[]{0, 253, 9, 1, 14, 13, 2, 3, 5, 4, 6, 7, 10, 11, 17, 15, 8}
|
||||||
),
|
),
|
||||||
HOURLY_WEATHER_FORECAST(9, GlobalFITMessage.WEATHER,
|
HOURLY_WEATHER_FORECAST(9, GlobalFITMessage.WEATHER,
|
||||||
new int[]{0, 253, 1, 2, 3, 4, 5, 7, 15, 16, 17}
|
new int[]{0, 253, 1, 2, 3, 4, 5, 6, 7, 15, 16, 17}
|
||||||
),
|
),
|
||||||
DAILY_WEATHER_FORECAST(10, GlobalFITMessage.WEATHER,
|
DAILY_WEATHER_FORECAST(10, GlobalFITMessage.WEATHER,
|
||||||
new int[]{0, 253, 14, 13, 2, 5, 12}
|
new int[]{0, 253, 14, 13, 2, 5, 12, 17}
|
||||||
);
|
);
|
||||||
|
|
||||||
private final int type;
|
private final int type;
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FieldDefinition;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.baseTypes.BaseType;
|
||||||
|
|
||||||
|
public class FieldDefinitionWeatherAqi extends FieldDefinition {
|
||||||
|
|
||||||
|
public FieldDefinitionWeatherAqi(int localNumber, int size, BaseType baseType, String name) {
|
||||||
|
super(localNumber, size, baseType, name, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object decode(ByteBuffer byteBuffer) {
|
||||||
|
int idx = (int) baseType.decode(byteBuffer, scale, offset);
|
||||||
|
return AQI_LEVELS.values()[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encode(ByteBuffer byteBuffer, Object o) {
|
||||||
|
if (o instanceof AQI_LEVELS) {
|
||||||
|
baseType.encode(byteBuffer, ((AQI_LEVELS) o).ordinal(), scale, offset);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
baseType.encode(byteBuffer, aqiAbsoluteValueToIndex((int) o), scale, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int aqiAbsoluteValueToIndex(int rawValue) { //see https://github.com/breezy-weather/breezy-weather/blob/main/app/src/main/java/org/breezyweather/domain/weather/index/PollutantIndex.kt#L38
|
||||||
|
if (rawValue == -1) {
|
||||||
|
return rawValue; //invalid
|
||||||
|
}
|
||||||
|
if (rawValue < 20) {
|
||||||
|
return AQI_LEVELS.GOOD.ordinal();
|
||||||
|
} else if (rawValue < 50) {
|
||||||
|
return AQI_LEVELS.MODERATE.ordinal();
|
||||||
|
} else if (rawValue < 100) {
|
||||||
|
return AQI_LEVELS.UNHEALTHY_SENSITIVE.ordinal();
|
||||||
|
} else if (rawValue < 150) {
|
||||||
|
return AQI_LEVELS.UNHEALTHY.ordinal();
|
||||||
|
} else if (rawValue < 250) {
|
||||||
|
return AQI_LEVELS.VERY_UNHEALTHY.ordinal();
|
||||||
|
} else {
|
||||||
|
return AQI_LEVELS.HAZARDOUS.ordinal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum AQI_LEVELS {
|
||||||
|
GOOD,
|
||||||
|
MODERATE,
|
||||||
|
UNHEALTHY_SENSITIVE,
|
||||||
|
UNHEALTHY,
|
||||||
|
VERY_UNHEALTHY,
|
||||||
|
HAZARDOUS,
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user