diff --git a/app/src/main/java/cz/martykan/forecastie/AlarmReceiver.java b/app/src/main/java/cz/martykan/forecastie/AlarmReceiver.java index 36917368..1a088746 100644 --- a/app/src/main/java/cz/martykan/forecastie/AlarmReceiver.java +++ b/app/src/main/java/cz/martykan/forecastie/AlarmReceiver.java @@ -146,6 +146,7 @@ protected Void doInBackground(String... params) { protected void onPostExecute(Void v) { // Update widgets AbstractWidgetProvider.updateWidgets(context); + Broadcaster.sendWeather(context); } } @@ -188,7 +189,7 @@ protected Void doInBackground(String... params) { } protected void onPostExecute(Void v) { - + Broadcaster.sendWeather(context); } } diff --git a/app/src/main/java/cz/martykan/forecastie/Broadcaster.java b/app/src/main/java/cz/martykan/forecastie/Broadcaster.java new file mode 100644 index 00000000..d3f11dd3 --- /dev/null +++ b/app/src/main/java/cz/martykan/forecastie/Broadcaster.java @@ -0,0 +1,123 @@ +package cz.martykan.forecastie; + +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; +import android.widget.Toast; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +import cz.martykan.forecastie.models.Weather; +import cz.martykan.forecastie.utils.UnitConvertor; +import cz.martykan.forecastie.weatherapi.WeatherStorage; +import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; + +public class Broadcaster { + public static void sendWeather(Context context) { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); + boolean run = sp.getBoolean("sendToApp", false); + + if(run) { + WeatherStorage storage = new WeatherStorage(context); + + Intent intent = new Intent(); + intent.setAction(sp.getString("sendAction", "de.kaffeemitkoffein.broadcast.WEATHERDATA")); + intent.setPackage(sp.getString("sendPackage","nodomain.freeyourgadget.gadgetbridge")); + intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); + intent.putExtra("WeatherSpec", generateWeatherSpec(storage)); + context.sendBroadcast(intent); + } + } + + private static WeatherSpec generateWeatherSpec(WeatherStorage storage) { + WeatherSpec spec = new WeatherSpec(); + Weather weather = storage.getLastToday(); + List multi = storage.getLastLongTerm(); + List forecasts = generateForecasts(weather, multi); + + spec.timestamp = (int) weather.getLastUpdated(); + spec.location = weather.getCity() + ", " +weather.getCountry(); + spec.currentTemp = (int) weather.getTemperature(); //Gadgetbridge does conversion. slight loss in accuracy here. + spec.currentConditionCode = weather.getWeatherId(); + spec.currentCondition = weather.getDescription(); + spec.currentHumidity = weather.getHumidity(); + spec.todayMaxTemp = forecasts.get(0).maxTemp; + spec.todayMinTemp = forecasts.get(0).minTemp; + spec.windSpeed = (float) weather.getWind(); //km per hour. + spec.windDirection = weather.getWindDirectionDegree().intValue(); + for (int i=1;i generateForecasts(Weather weather, List manyWeathers) { + List forecasts = new ArrayList(); + manyWeathers.add(0,weather); + List allWeathers = manyWeathers; + + //seperate weathers out based on day. assuming already ordered, no further sorting based on day is needed. + List> sortedWeathers = new ArrayList>(); + Calendar currCal; + Calendar currDate; + int count=0; + + while(count()); + + for(int i=0;i dayNumber : sortedWeathers) + { + ArrayList temps = new ArrayList(); + int totalHumid = 0; + + for (Integer occ : dayNumber) { + temps.add(allWeathers.get(occ).getTemperature()); + totalHumid += allWeathers.get(occ).getHumidity(); + } + + int humidity = totalHumid / dayNumber.size(); + //TODO also the option to take mode of weather conditions for the day instead of just getting mid value + int condition = allWeathers.get(dayNumber.get(dayNumber.size() / 2)).getWeatherId(); + double maxTemp = temps.get(0); + double minTemp = temps.get(0); + + for(double temp : temps) + { + if(temp < minTemp) + minTemp = temp; + if(temp > maxTemp) + maxTemp = temp; + } + + WeatherSpec.Forecast forecast = new WeatherSpec.Forecast( + (int) minTemp, + (int) maxTemp, + condition, + humidity); + forecasts.add(forecast); + } + return forecasts; + } + //method from LongTermWeatherList + private static Calendar getWeatherCalendar(Weather weather) { + Calendar weatherCalendar = Calendar.getInstance(); + weatherCalendar.setTimeInMillis(weather.getDate().getTime()); + + return weatherCalendar; + } +} diff --git a/app/src/main/java/cz/martykan/forecastie/activities/MainActivity.java b/app/src/main/java/cz/martykan/forecastie/activities/MainActivity.java index 0a32d0b3..895cae8c 100644 --- a/app/src/main/java/cz/martykan/forecastie/activities/MainActivity.java +++ b/app/src/main/java/cz/martykan/forecastie/activities/MainActivity.java @@ -54,6 +54,7 @@ import java.util.Map; import cz.martykan.forecastie.AlarmReceiver; +import cz.martykan.forecastie.Broadcaster; import cz.martykan.forecastie.Constants; import cz.martykan.forecastie.R; import cz.martykan.forecastie.adapters.ViewPagerAdapter; @@ -746,6 +747,7 @@ protected void onPostExecute(TaskOutput output) { super.onPostExecute(output); // Update widgets AbstractWidgetProvider.updateWidgets(context); + Broadcaster.sendWeather(context); } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/WeatherSpec.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/WeatherSpec.java new file mode 100644 index 00000000..b35a51a5 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/WeatherSpec.java @@ -0,0 +1,156 @@ +/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele + Gobbetti + + 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 . */ + +package nodomain.freeyourgadget.gadgetbridge.model; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.Arrays; + +// FIXME: document me and my fields, including units +public class WeatherSpec implements Parcelable { + public static final Creator CREATOR = new Creator() { + @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 = 2; + public int timestamp; + public String location; + public int currentTemp; + public int currentConditionCode = 3200; + public String currentCondition; + public int currentHumidity; + public int todayMaxTemp; + public int todayMinTemp; + public float windSpeed; //km per hour + public int windDirection; //deg + + public ArrayList forecasts = 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 int windSpeedAsBeaufort() { + int l = 0; + while (l < beaufort.length && beaufort[l] < this.windSpeed) { + l++; + } + return l; + } + + protected WeatherSpec(Parcel in) { + int version = in.readInt(); + if (version == VERSION) { + 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(); + in.readList(forecasts, Forecast.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); + } + + public static class Forecast implements Parcelable { + public static final Creator CREATOR = new Creator() { + @Override + public Forecast createFromParcel(Parcel in) { + return new Forecast(in); + } + + @Override + public Forecast[] newArray(int size) { + return new Forecast[size]; + } + }; + public int minTemp; + public int maxTemp; + public int conditionCode; + 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); + } + } +} diff --git a/app/src/main/res/xml/prefs.xml b/app/src/main/res/xml/prefs.xml index eb00d437..148113aa 100644 --- a/app/src/main/res/xml/prefs.xml +++ b/app/src/main/res/xml/prefs.xml @@ -88,6 +88,23 @@ android:key="refreshInterval" android:title="@string/setting_refreshInterval" /> + + + + + +