mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-12-26 10:35:50 +01:00
Add support for multiple weather locations
Introduce the concept of primary and secondary weathers: * Primary weather keeps the same behavior as previously across all weather providers, so it's non-breaking. This location is not necessarily the current location, just the primary weather location set by the user. * The GenericWeatherReceiver now has a new extra WeatherSecondaryJson, that receives a json list with secondary weather locations. It's guaranteed that the primary weather always exists, so the list of WeatherSpecs provided to devices is never empty. Update all support classes accordingly.
This commit is contained in:
parent
57fd857de5
commit
81aef0bf35
@ -374,10 +374,9 @@ public class DebugActivity extends AbstractGBActivity {
|
|||||||
weatherSpec.forecasts.add(gbForecast);
|
weatherSpec.forecasts.add(gbForecast);
|
||||||
}
|
}
|
||||||
|
|
||||||
Weather.getInstance().setWeatherSpec(weatherSpec);
|
Weather.getInstance().setWeatherSpec(new ArrayList<>(Collections.singletonList(weatherSpec)));
|
||||||
}
|
}
|
||||||
|
GBApplication.deviceService().onSendWeather(new ArrayList<>(Collections.singletonList(Weather.getInstance().getWeatherSpec())));
|
||||||
GBApplication.deviceService().onSendWeather(Weather.getInstance().getWeatherSpec());
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -385,18 +384,27 @@ public class DebugActivity extends AbstractGBActivity {
|
|||||||
showCachedWeatherButton.setOnClickListener(new View.OnClickListener(){
|
showCachedWeatherButton.setOnClickListener(new View.OnClickListener(){
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
final String weatherInfo = getWeatherInfo();
|
final List<WeatherSpec> weatherSpecs = Weather.getInstance().getWeatherSpecs();
|
||||||
|
|
||||||
|
if (weatherSpecs == null || weatherSpecs.isEmpty()) {
|
||||||
|
displayWeatherInfo(null);
|
||||||
|
return;
|
||||||
|
} else if (weatherSpecs.size() == 1) {
|
||||||
|
displayWeatherInfo(weatherSpecs.get(0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String[] weatherLocations = new String[weatherSpecs.size()];
|
||||||
|
|
||||||
|
for (int i = 0; i < weatherSpecs.size(); i++) {
|
||||||
|
weatherLocations[i] = weatherSpecs.get(i).location;
|
||||||
|
}
|
||||||
|
|
||||||
new MaterialAlertDialogBuilder(DebugActivity.this)
|
new MaterialAlertDialogBuilder(DebugActivity.this)
|
||||||
.setCancelable(true)
|
.setCancelable(true)
|
||||||
.setTitle("Cached Weather Data")
|
.setTitle("Choose Location")
|
||||||
.setMessage(weatherInfo)
|
.setItems(weatherLocations, (dialog, which) -> displayWeatherInfo(weatherSpecs.get(which)))
|
||||||
.setPositiveButton(R.string.ok, (dialog, which) -> {
|
.setNegativeButton("Cancel", (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();
|
.show();
|
||||||
}
|
}
|
||||||
@ -1045,14 +1053,30 @@ public class DebugActivity extends AbstractGBActivity {
|
|||||||
return TextUtils.join(separator, mac).toUpperCase(Locale.ROOT);
|
return TextUtils.join(separator, mac).toUpperCase(Locale.ROOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getWeatherInfo() {
|
private void displayWeatherInfo(final WeatherSpec weatherSpec) {
|
||||||
|
final String weatherInfo = getWeatherInfo(weatherSpec);
|
||||||
|
|
||||||
|
new MaterialAlertDialogBuilder(DebugActivity.this)
|
||||||
|
.setCancelable(true)
|
||||||
|
.setTitle("Cached Weather Data")
|
||||||
|
.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();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getWeatherInfo(final WeatherSpec weatherSpec) {
|
||||||
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.ROOT);
|
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.ROOT);
|
||||||
|
|
||||||
final StringBuilder builder = new StringBuilder();
|
final StringBuilder builder = new StringBuilder();
|
||||||
WeatherSpec weatherSpec = Weather.getInstance().getWeatherSpec();
|
|
||||||
|
|
||||||
if (weatherSpec == null)
|
if (weatherSpec == null)
|
||||||
return "Weather cache is empty...";
|
return "Weather cache is empty.";
|
||||||
|
|
||||||
builder.append("Location: ").append(weatherSpec.location).append("\n");
|
builder.append("Location: ").append(weatherSpec.location).append("\n");
|
||||||
builder.append("Timestamp: ").append(weatherSpec.timestamp).append("\n");
|
builder.append("Timestamp: ").append(weatherSpec.timestamp).append("\n");
|
||||||
|
@ -135,7 +135,7 @@ public interface EventHandler {
|
|||||||
|
|
||||||
void onTestNewFunction();
|
void onTestNewFunction();
|
||||||
|
|
||||||
void onSendWeather(WeatherSpec weatherSpec);
|
void onSendWeather(ArrayList<WeatherSpec> weatherSpecs);
|
||||||
|
|
||||||
void onSetFmFrequency(float frequency);
|
void onSetFmFrequency(float frequency);
|
||||||
|
|
||||||
|
@ -260,7 +260,8 @@ public class SMAQ2OSSSupport extends AbstractBTLEDeviceSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
public void onSendWeather(ArrayList<WeatherSpec> weatherSpecs) {
|
||||||
|
WeatherSpec weatherSpec = weatherSpecs.get(0);
|
||||||
try {
|
try {
|
||||||
TransactionBuilder builder;
|
TransactionBuilder builder;
|
||||||
builder = performInitialized("Sending current weather");
|
builder = performInitialized("Sending current weather");
|
||||||
|
@ -28,6 +28,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import cyanogenmod.weather.CMWeatherManager;
|
import cyanogenmod.weather.CMWeatherManager;
|
||||||
@ -176,8 +177,9 @@ public class CMWeatherReceiver extends BroadcastReceiver implements CMWeatherMan
|
|||||||
gbForecast.conditionCode = Weather.mapToOpenWeatherMapCondition(CMtoYahooCondintion(cmForecast.getConditionCode()));
|
gbForecast.conditionCode = Weather.mapToOpenWeatherMapCondition(CMtoYahooCondintion(cmForecast.getConditionCode()));
|
||||||
weatherSpec.forecasts.add(gbForecast);
|
weatherSpec.forecasts.add(gbForecast);
|
||||||
}
|
}
|
||||||
Weather.getInstance().setWeatherSpec(weatherSpec);
|
ArrayList<WeatherSpec> weatherSpecs = new ArrayList<>(Collections.singletonList(weatherSpec));
|
||||||
GBApplication.deviceService().onSendWeather(weatherSpec);
|
Weather.getInstance().setWeatherSpec(weatherSpecs);
|
||||||
|
GBApplication.deviceService().onSendWeather(weatherSpecs);
|
||||||
} else {
|
} else {
|
||||||
LOG.info("request has returned null for WeatherInfo");
|
LOG.info("request has returned null for WeatherInfo");
|
||||||
}
|
}
|
||||||
|
@ -25,11 +25,13 @@ import android.os.Bundle;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
|
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
|
||||||
@ -41,111 +43,143 @@ public class GenericWeatherReceiver extends BroadcastReceiver {
|
|||||||
|
|
||||||
public final static String ACTION_GENERIC_WEATHER = "nodomain.freeyourgadget.gadgetbridge.ACTION_GENERIC_WEATHER";
|
public final static String ACTION_GENERIC_WEATHER = "nodomain.freeyourgadget.gadgetbridge.ACTION_GENERIC_WEATHER";
|
||||||
public final static String EXTRA_WEATHER_JSON = "WeatherJson";
|
public final static String EXTRA_WEATHER_JSON = "WeatherJson";
|
||||||
|
public final static String EXTRA_WEATHER_SECONDARY_JSON = "WeatherSecondaryJson";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
if (intent != null && ACTION_GENERIC_WEATHER.equals(intent.getAction())) {
|
if (intent == null) {
|
||||||
Bundle bundle = intent.getExtras();
|
LOG.warn("Intent is null");
|
||||||
if (bundle != null && bundle.containsKey(EXTRA_WEATHER_JSON)) {
|
return;
|
||||||
try {
|
}
|
||||||
JSONObject weatherJson = new JSONObject(bundle.getString(EXTRA_WEATHER_JSON));
|
|
||||||
|
|
||||||
WeatherSpec weatherSpec = new WeatherSpec();
|
if (!ACTION_GENERIC_WEATHER.equals(intent.getAction())) {
|
||||||
|
LOG.warn("Unknown action {}", intent.getAction());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
weatherSpec.timestamp = safelyGet(weatherJson, Integer.class, "timestamp", (int) (System.currentTimeMillis() / 1000));
|
final Bundle bundle = intent.getExtras();
|
||||||
weatherSpec.location = safelyGet(weatherJson, String.class, "location", "");
|
if (bundle == null) {
|
||||||
weatherSpec.currentTemp = safelyGet(weatherJson, Integer.class, "currentTemp", 0);
|
LOG.warn("Intent has no extras");
|
||||||
weatherSpec.todayMinTemp = safelyGet(weatherJson, Integer.class, "todayMinTemp", 0);
|
return;
|
||||||
weatherSpec.todayMaxTemp = safelyGet(weatherJson, Integer.class, "todayMaxTemp", 0);
|
}
|
||||||
weatherSpec.currentCondition = safelyGet(weatherJson, String.class, "currentCondition", "");
|
|
||||||
weatherSpec.currentConditionCode = safelyGet(weatherJson, Integer.class, "currentConditionCode", 0);
|
|
||||||
weatherSpec.currentHumidity = safelyGet(weatherJson, Integer.class, "currentHumidity", 0);
|
|
||||||
weatherSpec.windSpeed = safelyGet(weatherJson, Number.class, "windSpeed", 0d).floatValue();
|
|
||||||
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")) {
|
if (!bundle.containsKey(EXTRA_WEATHER_JSON)) {
|
||||||
weatherSpec.airQuality = toAirQuality(weatherJson.getJSONObject("airQuality"));
|
LOG.warn("Bundle key {} not found", EXTRA_WEATHER_JSON);
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (weatherJson.has("forecasts")) {
|
try {
|
||||||
JSONArray forecastArray = weatherJson.getJSONArray("forecasts");
|
final JSONObject primaryWeatherJson = new JSONObject(Objects.requireNonNull(bundle.getString(EXTRA_WEATHER_JSON)));
|
||||||
weatherSpec.forecasts = new ArrayList<>();
|
final WeatherSpec primaryWeather = weatherFromJson(primaryWeatherJson);
|
||||||
|
|
||||||
for (int i = 0, l = forecastArray.length(); i < l; i++) {
|
final ArrayList<WeatherSpec> weathers = new ArrayList<>();
|
||||||
JSONObject forecastJson = forecastArray.getJSONObject(i);
|
weathers.add(primaryWeather);
|
||||||
|
|
||||||
WeatherSpec.Daily forecast = new WeatherSpec.Daily();
|
if (bundle.containsKey(EXTRA_WEATHER_SECONDARY_JSON)) {
|
||||||
|
final JSONArray secondaryWeatherJson = new JSONArray(bundle.getString(EXTRA_WEATHER_SECONDARY_JSON, "[]"));
|
||||||
|
|
||||||
forecast.conditionCode = safelyGet(forecastJson, Integer.class, "conditionCode", 0);
|
for (int i = 0; i < secondaryWeatherJson.length(); i++) {
|
||||||
forecast.humidity = safelyGet(forecastJson, Integer.class, "humidity", 0);
|
weathers.add(weatherFromJson(secondaryWeatherJson.getJSONObject(i)));
|
||||||
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(forecastJson, Number.class, "uvIndex", 0d).floatValue();
|
|
||||||
forecast.precipProbability = safelyGet(forecastJson, 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(forecastJson, Number.class, "uvIndex", 0d).floatValue();
|
|
||||||
forecast.precipProbability = safelyGet(forecastJson, Integer.class, "precipProbability", 0);
|
|
||||||
|
|
||||||
weatherSpec.hourly.add(forecast);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG.info("Got generic weather for {}", weatherSpec.location);
|
|
||||||
|
|
||||||
Weather.getInstance().setWeatherSpec(weatherSpec);
|
|
||||||
GBApplication.deviceService().onSendWeather(weatherSpec);
|
|
||||||
} catch (Exception e) {
|
|
||||||
GB.toast("Gadgetbridge received broken or incompatible weather data", Toast.LENGTH_SHORT, GB.ERROR, e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG.info("Got generic weather for {} locations", weathers.size());
|
||||||
|
Weather.getInstance().setWeatherSpec(weathers);
|
||||||
|
GBApplication.deviceService().onSendWeather(weathers);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
GB.toast("Gadgetbridge received broken or incompatible weather data", Toast.LENGTH_SHORT, GB.ERROR, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private WeatherSpec weatherFromJson(final JSONObject weatherJson) throws JSONException {
|
||||||
|
final WeatherSpec weatherSpec = new WeatherSpec();
|
||||||
|
|
||||||
|
weatherSpec.timestamp = safelyGet(weatherJson, Integer.class, "timestamp", (int) (System.currentTimeMillis() / 1000));
|
||||||
|
weatherSpec.location = safelyGet(weatherJson, String.class, "location", "");
|
||||||
|
weatherSpec.currentTemp = safelyGet(weatherJson, Integer.class, "currentTemp", 0);
|
||||||
|
weatherSpec.todayMinTemp = safelyGet(weatherJson, Integer.class, "todayMinTemp", 0);
|
||||||
|
weatherSpec.todayMaxTemp = safelyGet(weatherJson, Integer.class, "todayMaxTemp", 0);
|
||||||
|
weatherSpec.currentCondition = safelyGet(weatherJson, String.class, "currentCondition", "");
|
||||||
|
weatherSpec.currentConditionCode = safelyGet(weatherJson, Integer.class, "currentConditionCode", 0);
|
||||||
|
weatherSpec.currentHumidity = safelyGet(weatherJson, Integer.class, "currentHumidity", 0);
|
||||||
|
weatherSpec.windSpeed = safelyGet(weatherJson, Number.class, "windSpeed", 0d).floatValue();
|
||||||
|
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")) {
|
||||||
|
final JSONArray forecastArray = weatherJson.getJSONArray("forecasts");
|
||||||
|
weatherSpec.forecasts = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int i = 0, l = forecastArray.length(); i < l; i++) {
|
||||||
|
final JSONObject forecastJson = forecastArray.getJSONObject(i);
|
||||||
|
|
||||||
|
final 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(forecastJson, Number.class, "uvIndex", 0d).floatValue();
|
||||||
|
forecast.precipProbability = safelyGet(forecastJson, 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")) {
|
||||||
|
final JSONArray forecastArray = weatherJson.getJSONArray("hourly");
|
||||||
|
weatherSpec.hourly = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int i = 0, l = forecastArray.length(); i < l; i++) {
|
||||||
|
final JSONObject forecastJson = forecastArray.getJSONObject(i);
|
||||||
|
|
||||||
|
final 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(forecastJson, Number.class, "uvIndex", 0d).floatValue();
|
||||||
|
forecast.precipProbability = safelyGet(forecastJson, Integer.class, "precipProbability", 0);
|
||||||
|
|
||||||
|
weatherSpec.hourly.add(forecast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return weatherSpec;
|
||||||
|
}
|
||||||
|
|
||||||
private WeatherSpec.AirQuality toAirQuality(final JSONObject jsonObject) {
|
private WeatherSpec.AirQuality toAirQuality(final JSONObject jsonObject) {
|
||||||
final WeatherSpec.AirQuality airQuality = new WeatherSpec.AirQuality();
|
final WeatherSpec.AirQuality airQuality = new WeatherSpec.AirQuality();
|
||||||
airQuality.aqi = safelyGet(jsonObject, Integer.class, "aqi", -1);
|
airQuality.aqi = safelyGet(jsonObject, Integer.class, "aqi", -1);
|
||||||
|
@ -40,6 +40,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import lineageos.weather.LineageWeatherManager;
|
import lineageos.weather.LineageWeatherManager;
|
||||||
@ -201,8 +202,9 @@ public class LineageOsWeatherReceiver extends BroadcastReceiver implements Linea
|
|||||||
gbForecast.conditionCode = Weather.mapToOpenWeatherMapCondition(LineageOSToYahooCondition(cmForecast.getConditionCode()));
|
gbForecast.conditionCode = Weather.mapToOpenWeatherMapCondition(LineageOSToYahooCondition(cmForecast.getConditionCode()));
|
||||||
weatherSpec.forecasts.add(gbForecast);
|
weatherSpec.forecasts.add(gbForecast);
|
||||||
}
|
}
|
||||||
Weather.getInstance().setWeatherSpec(weatherSpec);
|
ArrayList<WeatherSpec> weatherSpecs = new ArrayList<>(Collections.singletonList(weatherSpec));
|
||||||
GBApplication.deviceService().onSendWeather(weatherSpec);
|
Weather.getInstance().setWeatherSpec(weatherSpecs);
|
||||||
|
GBApplication.deviceService().onSendWeather(weatherSpecs);
|
||||||
} else {
|
} else {
|
||||||
LOG.info("request has returned null for WeatherInfo");
|
LOG.info("request has returned null for WeatherInfo");
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,8 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
|
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
|
||||||
@ -136,8 +138,9 @@ public class OmniJawsObserver extends ContentObserver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Weather.getInstance().setWeatherSpec(weatherSpec);
|
ArrayList<WeatherSpec> weatherSpecs = new ArrayList<>(Collections.singletonList(weatherSpec));
|
||||||
GBApplication.deviceService().onSendWeather(weatherSpec);
|
Weather.getInstance().setWeatherSpec(weatherSpecs);
|
||||||
|
GBApplication.deviceService().onSendWeather(weatherSpecs);
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
c.close();
|
c.close();
|
||||||
|
@ -23,6 +23,9 @@ import android.content.Intent;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
|
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||||
@ -38,9 +41,10 @@ public class TinyWeatherForecastGermanyReceiver extends BroadcastReceiver {
|
|||||||
try {
|
try {
|
||||||
WeatherSpec weatherSpec = bundle.getParcelable("WeatherSpec");
|
WeatherSpec weatherSpec = bundle.getParcelable("WeatherSpec");
|
||||||
if (weatherSpec != null) {
|
if (weatherSpec != null) {
|
||||||
Weather.getInstance().setWeatherSpec(weatherSpec);
|
ArrayList<WeatherSpec> weatherSpecs = new ArrayList<>(Collections.singletonList(weatherSpec));
|
||||||
weatherSpec.timestamp = (int) (System.currentTimeMillis() / 1000);
|
weatherSpec.timestamp = (int) (System.currentTimeMillis() / 1000);
|
||||||
GBApplication.deviceService().onSendWeather(weatherSpec);
|
Weather.getInstance().setWeatherSpec(weatherSpecs);
|
||||||
|
GBApplication.deviceService().onSendWeather(weatherSpecs);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
GB.toast("Gadgetbridge received broken or incompatible weather data", Toast.LENGTH_SHORT, GB.ERROR, e);
|
GB.toast("Gadgetbridge received broken or incompatible weather data", Toast.LENGTH_SHORT, GB.ERROR, e);
|
||||||
|
@ -23,6 +23,9 @@ import android.content.Intent;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
|
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||||
@ -53,8 +56,9 @@ public class WeatherNotificationReceiver extends BroadcastReceiver {
|
|||||||
WeatherSpec weatherSpec = parcelableWeather2.weatherSpec;
|
WeatherSpec weatherSpec = parcelableWeather2.weatherSpec;
|
||||||
LOG.info("weather in " + weatherSpec.location + " is " + weatherSpec.currentCondition + " (" + (weatherSpec.currentTemp - 273) + "°C)");
|
LOG.info("weather in " + weatherSpec.location + " is " + weatherSpec.currentCondition + " (" + (weatherSpec.currentTemp - 273) + "°C)");
|
||||||
|
|
||||||
Weather.getInstance().setWeatherSpec(weatherSpec);
|
ArrayList<WeatherSpec> weatherSpecs = new ArrayList<>(Collections.singletonList(weatherSpec));
|
||||||
GBApplication.deviceService().onSendWeather(weatherSpec);
|
Weather.getInstance().setWeatherSpec(weatherSpecs);
|
||||||
|
GBApplication.deviceService().onSendWeather(weatherSpecs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -488,9 +488,9 @@ public class GBDeviceService implements DeviceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
public void onSendWeather(ArrayList<WeatherSpec> weatherSpecs) {
|
||||||
Intent intent = createIntent().setAction(ACTION_SEND_WEATHER)
|
Intent intent = createIntent().setAction(ACTION_SEND_WEATHER)
|
||||||
.putExtra(EXTRA_WEATHER, (Parcelable) weatherSpec);
|
.putExtra(EXTRA_WEATHER, weatherSpecs);
|
||||||
invokeService(intent);
|
invokeService(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
package nodomain.freeyourgadget.gadgetbridge.model;
|
package nodomain.freeyourgadget.gadgetbridge.model;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
@ -26,28 +28,47 @@ import org.slf4j.LoggerFactory;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
import java.io.ObjectOutputStream;
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.io.ObjectStreamException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class Weather {
|
public class Weather {
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(Weather.class);
|
private static final Logger LOG = LoggerFactory.getLogger(Weather.class);
|
||||||
|
|
||||||
private WeatherSpec weatherSpec = null;
|
private final ArrayList<WeatherSpec> weatherSpecs = new ArrayList<>();
|
||||||
|
|
||||||
private JSONObject reconstructedOWMForecast = null;
|
private JSONObject reconstructedOWMForecast = null;
|
||||||
|
|
||||||
private File cacheFile;
|
private File cacheFile;
|
||||||
|
|
||||||
public WeatherSpec getWeatherSpec() {
|
private Weather() {
|
||||||
return weatherSpec;
|
// Use getInstance
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setWeatherSpec(WeatherSpec weatherSpec) {
|
@Nullable
|
||||||
this.weatherSpec = weatherSpec;
|
public WeatherSpec getWeatherSpec() {
|
||||||
|
if (weatherSpecs.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return weatherSpecs.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<WeatherSpec> getWeatherSpecs() {
|
||||||
|
return weatherSpecs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWeatherSpec(final List<WeatherSpec> newWeatherSpecs) {
|
||||||
|
weatherSpecs.clear();
|
||||||
|
weatherSpecs.addAll(newWeatherSpecs);
|
||||||
saveToCache();
|
saveToCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject createReconstructedOWMWeatherReply() {
|
public JSONObject createReconstructedOWMWeatherReply() {
|
||||||
|
final WeatherSpec weatherSpec = getWeatherSpec();
|
||||||
if (weatherSpec == null) {
|
if (weatherSpec == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -208,6 +229,7 @@ public class Weather {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int mapToYahooCondition(int openWeatherMapCondition) {
|
public static int mapToYahooCondition(int openWeatherMapCondition) {
|
||||||
// openweathermap.org conditions:
|
// openweathermap.org conditions:
|
||||||
// http://openweathermap.org/weather-conditions
|
// http://openweathermap.org/weather-conditions
|
||||||
@ -1133,24 +1155,29 @@ public class Weather {
|
|||||||
* @param enabled whether caching is enabled
|
* @param enabled whether caching is enabled
|
||||||
*/
|
*/
|
||||||
public void setCacheFile(final File cacheDir, final boolean enabled) {
|
public void setCacheFile(final File cacheDir, final boolean enabled) {
|
||||||
|
// FIXME: Do not use serializable for this
|
||||||
|
|
||||||
cacheFile = new File(cacheDir, "weatherCache.bin");
|
cacheFile = new File(cacheDir, "weatherCache.bin");
|
||||||
|
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
LOG.info("Setting weather cache file to {}", cacheFile.getPath());
|
LOG.info("Setting weather cache file to {}", cacheFile.getPath());
|
||||||
|
|
||||||
if (cacheFile.isFile() && weatherSpec == null) {
|
if (cacheFile.isFile() && weatherSpecs.isEmpty()) {
|
||||||
try (final FileInputStream f = new FileInputStream(cacheFile)) {
|
try (final ObjectInputStream o = new ObjectInputStream(new FileInputStream(cacheFile))) {
|
||||||
final ObjectInputStream o = new ObjectInputStream(f);
|
final ArrayList<WeatherSpec> cachedSpecs = (ArrayList<WeatherSpec>) o.readObject();
|
||||||
|
weatherSpecs.addAll(cachedSpecs);
|
||||||
weatherSpec = (WeatherSpec) o.readObject();
|
} catch (final ObjectStreamException e) {
|
||||||
|
LOG.error("Failed to deserialize weather from cache", e);
|
||||||
o.close();
|
// keep cacheFile set - it's most likely an older version
|
||||||
|
} catch (final IOException e) {
|
||||||
|
LOG.error("Failed to read weather cache file", e);
|
||||||
|
// Something is wrong with the file
|
||||||
|
cacheFile = null;
|
||||||
} catch (final Throwable e) {
|
} catch (final Throwable e) {
|
||||||
LOG.error("Failed to read weather from cache", e);
|
LOG.error("Failed to read weather from cache", e);
|
||||||
weatherSpec = null;
|
// keep cacheFile set - it's most likely an older version
|
||||||
cacheFile = null;
|
|
||||||
}
|
}
|
||||||
} else if (weatherSpec != null) {
|
} else if (!weatherSpecs.isEmpty()) {
|
||||||
saveToCache();
|
saveToCache();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1171,20 +1198,14 @@ public class Weather {
|
|||||||
* Save the current weather to cache, if a cache file is enabled and the weather is not null.
|
* Save the current weather to cache, if a cache file is enabled and the weather is not null.
|
||||||
*/
|
*/
|
||||||
public void saveToCache() {
|
public void saveToCache() {
|
||||||
if (weatherSpec == null || cacheFile == null) {
|
if (weatherSpecs.isEmpty() || cacheFile == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG.info("Loading weather from cache {}", cacheFile.getPath());
|
LOG.info("Loading weather from cache {}", cacheFile.getPath());
|
||||||
|
|
||||||
try {
|
try (ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(cacheFile))) {
|
||||||
final FileOutputStream f = new FileOutputStream(cacheFile);
|
o.writeObject(weatherSpecs);
|
||||||
final ObjectOutputStream o = new ObjectOutputStream(f);
|
|
||||||
|
|
||||||
o.writeObject(weatherSpec);
|
|
||||||
|
|
||||||
o.close();
|
|
||||||
f.close();
|
|
||||||
} catch (final Throwable e) {
|
} catch (final Throwable e) {
|
||||||
LOG.error("Failed to save weather to cache", e);
|
LOG.error("Failed to save weather to cache", e);
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ public class WeatherSpec implements Parcelable, Serializable {
|
|||||||
public int sunSet; // unix epoch timestamp, in seconds
|
public int sunSet; // unix epoch timestamp, in seconds
|
||||||
public int moonRise; // unix epoch timestamp, in seconds
|
public int moonRise; // unix epoch timestamp, in seconds
|
||||||
public int moonSet; // unix epoch timestamp, in seconds
|
public int moonSet; // unix epoch timestamp, in seconds
|
||||||
public int moonPhase; // deg
|
public int moonPhase; // deg [0, 360[
|
||||||
public float latitude;
|
public float latitude;
|
||||||
public float longitude;
|
public float longitude;
|
||||||
public int feelsLikeTemp; // kelvin
|
public int feelsLikeTemp; // kelvin
|
||||||
|
@ -1156,11 +1156,13 @@ public abstract class AbstractDeviceSupport implements DeviceSupport {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* If the device can receive weather information, this method can be
|
* If the device can receive weather information, this method can be
|
||||||
* overridden and implemented by the device support class.
|
* overridden and implemented by the device support class. It's guaranteed
|
||||||
* @param weatherSpec weather information
|
* that there is always at least one weatherSpec, with the first being the
|
||||||
|
* primary weather (not necessarily current location).
|
||||||
|
* @param weatherSpecs weather information
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
public void onSendWeather(ArrayList<WeatherSpec> weatherSpecs) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1031,9 +1031,9 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ACTION_SEND_WEATHER: {
|
case ACTION_SEND_WEATHER: {
|
||||||
WeatherSpec weatherSpec = intent.getParcelableExtra(EXTRA_WEATHER);
|
ArrayList<WeatherSpec> weatherSpecs = (ArrayList<WeatherSpec>) intent.getSerializableExtra(EXTRA_WEATHER);
|
||||||
if (weatherSpec != null) {
|
if (weatherSpecs != null && !weatherSpecs.isEmpty()) {
|
||||||
deviceSupport.onSendWeather(weatherSpec);
|
deviceSupport.onSendWeather(weatherSpecs);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -474,11 +474,11 @@ public class ServiceDeviceSupport implements DeviceSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
public void onSendWeather(ArrayList<WeatherSpec> weatherSpecs) {
|
||||||
if (checkBusy("send weather event")) {
|
if (checkBusy("send weather events")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
delegate.onSendWeather(weatherSpec);
|
delegate.onSendWeather(weatherSpecs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -27,6 +27,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -215,7 +216,8 @@ public class AsteroidOSDeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
public void onSendWeather(ArrayList<WeatherSpec> weatherSpecs) {
|
||||||
|
WeatherSpec weatherSpec = weatherSpecs.get(0);
|
||||||
AsteroidOSWeather asteroidOSWeather = new AsteroidOSWeather(weatherSpec);
|
AsteroidOSWeather asteroidOSWeather = new AsteroidOSWeather(weatherSpec);
|
||||||
TransactionBuilder builder = new TransactionBuilder("send weather info");
|
TransactionBuilder builder = new TransactionBuilder("send weather info");
|
||||||
// Send city name
|
// Send city name
|
||||||
|
@ -1644,7 +1644,8 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
public void onSendWeather(ArrayList<WeatherSpec> weatherSpecs) {
|
||||||
|
WeatherSpec weatherSpec = weatherSpecs.get(0);
|
||||||
try {
|
try {
|
||||||
JSONObject o = new JSONObject();
|
JSONObject o = new JSONObject();
|
||||||
o.put("t", "weather");
|
o.put("t", "weather");
|
||||||
|
@ -584,7 +584,8 @@ public class CmfWatchProSupport extends AbstractBTLEDeviceSupport implements Cmf
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendWeather(final WeatherSpec weatherSpec) {
|
public void onSendWeather(final ArrayList<WeatherSpec> weatherSpecs) {
|
||||||
|
final WeatherSpec weatherSpec = weatherSpecs.get(0);
|
||||||
// TODO consider adjusting the condition code for clear/sunny so "clear" at night doesn't show a sunny icon (perhaps 23 decimal)?
|
// TODO consider adjusting the condition code for clear/sunny so "clear" at night doesn't show a sunny icon (perhaps 23 decimal)?
|
||||||
// Each weather entry takes up 9 bytes
|
// Each weather entry takes up 9 bytes
|
||||||
// There are 7 of those weather entries - 7*9 bytes
|
// There are 7 of those weather entries - 7*9 bytes
|
||||||
|
@ -550,7 +550,8 @@ public class FitProDeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
public void onSendWeather(ArrayList<WeatherSpec> weatherSpecs) {
|
||||||
|
WeatherSpec weatherSpec = weatherSpecs.get(0);
|
||||||
LOG.debug("FitPro send weather");
|
LOG.debug("FitPro send weather");
|
||||||
short todayMax = (short) (weatherSpec.todayMaxTemp - 273);
|
short todayMax = (short) (weatherSpec.todayMaxTemp - 273);
|
||||||
short todayMin = (short) (weatherSpec.todayMinTemp - 273);
|
short todayMin = (short) (weatherSpec.todayMinTemp - 273);
|
||||||
|
@ -584,7 +584,8 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
public void onSendWeather(ArrayList<WeatherSpec> weatherSpecs) {
|
||||||
|
WeatherSpec weatherSpec = weatherSpecs.get(0);
|
||||||
try {
|
try {
|
||||||
TransactionBuilder builder = performInitialized("sendWeather");
|
TransactionBuilder builder = performInitialized("sendWeather");
|
||||||
|
|
||||||
|
@ -3101,7 +3101,7 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
public void onSendWeather(ArrayList<WeatherSpec> weatherSpecs) {
|
||||||
final DeviceCoordinator coordinator = gbDevice.getDeviceCoordinator();
|
final DeviceCoordinator coordinator = gbDevice.getDeviceCoordinator();
|
||||||
if (!coordinator.supportsWeather()) {
|
if (!coordinator.supportsWeather()) {
|
||||||
return;
|
return;
|
||||||
@ -3118,6 +3118,8 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport implements
|
|||||||
supportsConditionString = false;
|
supportsConditionString = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final WeatherSpec weatherSpec = weatherSpecs.get(0);
|
||||||
|
|
||||||
MiBandConst.DistanceUnit unit = HuamiCoordinator.getDistanceUnit();
|
MiBandConst.DistanceUnit unit = HuamiCoordinator.getDistanceUnit();
|
||||||
int tz_offset_hours = SimpleTimeZone.getDefault().getOffset(weatherSpec.timestamp * 1000L) / (1000 * 60 * 60);
|
int tz_offset_hours = SimpleTimeZone.getDefault().getOffset(weatherSpec.timestamp * 1000L) / (1000 * 60 * 60);
|
||||||
try {
|
try {
|
||||||
|
@ -837,7 +837,9 @@ public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferSer
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendWeather(final WeatherSpec weatherSpec) {
|
public void onSendWeather(final ArrayList<WeatherSpec> weatherSpecs) {
|
||||||
|
final WeatherSpec weatherSpec = weatherSpecs.get(0);
|
||||||
|
|
||||||
// Weather is not sent directly to the bands, they send HTTP requests for each location.
|
// Weather is not sent directly to the bands, they send HTTP requests for each location.
|
||||||
// When we have a weather update, set the default location to that location on the band.
|
// When we have a weather update, set the default location to that location on the band.
|
||||||
// TODO: Support for multiple weather locations
|
// TODO: Support for multiple weather locations
|
||||||
|
@ -120,7 +120,7 @@ public class HuaweiBRSupport extends AbstractBTBRDeviceSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
public void onSendWeather(ArrayList<WeatherSpec> weatherSpecs) {
|
||||||
supportProvider.onSendWeather(weatherSpec);
|
supportProvider.onSendWeather(weatherSpecs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,7 @@ public class HuaweiLESupport extends AbstractBTLEDeviceSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
public void onSendWeather(ArrayList<WeatherSpec> weatherSpecs) {
|
||||||
supportProvider.onSendWeather(weatherSpec);
|
supportProvider.onSendWeather(weatherSpecs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1712,13 +1712,15 @@ public class HuaweiSupportProvider {
|
|||||||
return Weather.WeatherIcon.UNKNOWN;
|
return Weather.WeatherIcon.UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
public void onSendWeather(ArrayList<WeatherSpec> weatherSpecs) {
|
||||||
// Initialize weather settings and send weather
|
// Initialize weather settings and send weather
|
||||||
if (!getHuaweiCoordinator().supportsWeather()) {
|
if (!getHuaweiCoordinator().supportsWeather()) {
|
||||||
LOG.error("onSendWeather called while weather is not supported.");
|
LOG.error("onSendWeather called while weather is not supported.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WeatherSpec weatherSpec = weatherSpecs.get(0);
|
||||||
|
|
||||||
Weather.Settings weatherSettings = new Weather.Settings();
|
Weather.Settings weatherSettings = new Weather.Settings();
|
||||||
|
|
||||||
SendWeatherStartRequest weatherStartRequest = new SendWeatherStartRequest(this, weatherSettings);
|
SendWeatherStartRequest weatherStartRequest = new SendWeatherStartRequest(this, weatherSettings);
|
||||||
|
@ -1219,7 +1219,8 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
public void onSendWeather(ArrayList<WeatherSpec> weatherSpecs) {
|
||||||
|
WeatherSpec weatherSpec = weatherSpecs.get(0);
|
||||||
try {
|
try {
|
||||||
TransactionBuilder builder = performInitialized("setWeather");
|
TransactionBuilder builder = performInitialized("setWeather");
|
||||||
int currentTemp;
|
int currentTemp;
|
||||||
|
@ -1209,11 +1209,6 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyse and decode sensor data from ADXL362 accelerometer
|
* Analyse and decode sensor data from ADXL362 accelerometer
|
||||||
* @param value to decode
|
* @param value to decode
|
||||||
|
@ -226,9 +226,9 @@ public class PebbleSupport extends AbstractSerialDeviceSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
public void onSendWeather(ArrayList<WeatherSpec> weatherSpecs) {
|
||||||
if (reconnect()) {
|
if (reconnect()) {
|
||||||
super.onSendWeather(weatherSpec);
|
super.onSendWeather(weatherSpecs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1027,7 +1027,9 @@ public class PineTimeJFSupport extends AbstractBTLEDeviceSupport implements DfuL
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
public void onSendWeather(ArrayList<WeatherSpec> weatherSpecs) {
|
||||||
|
WeatherSpec weatherSpec = weatherSpecs.get(0);
|
||||||
|
|
||||||
if (this.firmwareVersionMajor < 1 || (this.firmwareVersionMajor == 1 && this.firmwareVersionMinor <= 7)) {
|
if (this.firmwareVersionMajor < 1 || (this.firmwareVersionMajor == 1 && this.firmwareVersionMinor <= 7)) {
|
||||||
// Not supported
|
// Not supported
|
||||||
return;
|
return;
|
||||||
|
@ -695,8 +695,8 @@ public class QHybridSupport extends QHybridBaseSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
public void onSendWeather(ArrayList<WeatherSpec> weatherSpecs) {
|
||||||
watchAdapter.onSendWeather(weatherSpec);
|
watchAdapter.onSendWeather(weatherSpecs.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -372,9 +372,4 @@ public class SoFlowSupport extends AbstractBTLEDeviceSupport {
|
|||||||
GB.toast("Error setting configuration", Toast.LENGTH_LONG, GB.ERROR, e);
|
GB.toast("Error setting configuration", Toast.LENGTH_LONG, GB.ERROR, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -599,7 +599,8 @@ public class SonyWena3DeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
public void onSendWeather(ArrayList<WeatherSpec> weatherSpecs) {
|
||||||
|
WeatherSpec weatherSpec = weatherSpecs.get(0);
|
||||||
if(weatherSpec.forecasts.size() < 4) return;
|
if(weatherSpec.forecasts.size() < 4) return;
|
||||||
|
|
||||||
ArrayList<WeatherDay> days = new ArrayList<>();
|
ArrayList<WeatherDay> days = new ArrayList<>();
|
||||||
|
@ -115,6 +115,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
@ -936,8 +937,8 @@ public class VivomoveHrSupport extends AbstractBTLEDeviceSupport implements File
|
|||||||
private boolean foreground;
|
private boolean foreground;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
public void onSendWeather(ArrayList<WeatherSpec> weatherSpecs) {
|
||||||
sendWeatherConditions(weatherSpec);
|
sendWeatherConditions(weatherSpecs.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Map<Integer, DirectoryEntry> filesToDownload = new ConcurrentHashMap<>();
|
private final Map<Integer, DirectoryEntry> filesToDownload = new ConcurrentHashMap<>();
|
||||||
|
@ -383,7 +383,8 @@ public class WaspOSDeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
public void onSendWeather(ArrayList<WeatherSpec> weatherSpecs) {
|
||||||
|
WeatherSpec weatherSpec = weatherSpecs.get(0);
|
||||||
try {
|
try {
|
||||||
JSONObject o = new JSONObject();
|
JSONObject o = new JSONObject();
|
||||||
o.put("t", "weather");
|
o.put("t", "weather");
|
||||||
|
@ -398,8 +398,8 @@ public class XiaomiSupport extends AbstractDeviceSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendWeather(final WeatherSpec weatherSpec) {
|
public void onSendWeather(final ArrayList<WeatherSpec> weatherSpecs) {
|
||||||
weatherService.onSendWeather(weatherSpec);
|
weatherService.onSendWeather(weatherSpecs.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -597,7 +597,8 @@ public class ZeTimeDeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
public void onSendWeather(ArrayList<WeatherSpec> weatherSpecs) {
|
||||||
|
WeatherSpec weatherSpec = weatherSpecs.get(0);
|
||||||
byte[] weather = new byte[weatherSpec.location.getBytes(StandardCharsets.UTF_8).length + 26]; // 26 bytes for weatherdata and overhead
|
byte[] weather = new byte[weatherSpec.location.getBytes(StandardCharsets.UTF_8).length + 26]; // 26 bytes for weatherdata and overhead
|
||||||
weather[0] = ZeTimeConstants.CMD_PREAMBLE;
|
weather[0] = ZeTimeConstants.CMD_PREAMBLE;
|
||||||
weather[1] = ZeTimeConstants.CMD_PUSH_WEATHER_DATA;
|
weather[1] = ZeTimeConstants.CMD_PUSH_WEATHER_DATA;
|
||||||
|
@ -264,7 +264,8 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
public void onSendWeather(ArrayList<WeatherSpec> weatherSpecs) {
|
||||||
|
WeatherSpec weatherSpec = weatherSpecs.get(0);
|
||||||
byte[] bytes = gbDeviceProtocol.encodeSendWeather(weatherSpec);
|
byte[] bytes = gbDeviceProtocol.encodeSendWeather(weatherSpec);
|
||||||
sendToDevice(bytes);
|
sendToDevice(bytes);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user