Hi,
I am wondering whether my approach to using GPS coordinates with the Open Weather Map API to make changes to the watch face layout is 1) correct (it is a bit difficult to test on a watch compared to the simulator), and 2) efficient. I want to fire the background event once every hour, but "instantly" (as soon as possible with the 5 min background event request limit) when the user checks their watch after visiting another screen.
This is the logic in my onTemporalEvent function in the background.mc file. I register it once every 60 mins, and it is meant to pick up the current location from the GPS; if it fails to do so, it gets the last lat/long data from the last successful API request. If those are unavailable then it uses a set of constant lat/long coordinates I've defined.
if (Activity.getActivityInfo().currentLocation == null)
{
Sys.println("current loc null");
lat = Application.getApp().getProperty("lat");
lon = Application.getApp().getProperty("lon");
if (lat == null || lon == null)
{
//read fixed home coordinates
lat = home_lat;
lon = home_lon;
Sys.println("home coords");
}
}
else
{
Sys.println("got coords!");
lat = Activity.getActivityInfo().currentLocation.toDegrees()[0];
lon = Activity.getActivityInfo().currentLocation.toDegrees()[1];
}
Then I launch a OWM API request (using the code here), and this is my receive function:
dict = {};
...
function receiveWeather(responseCode, data) {
if (responseCode == 200)// && data instanceof Dictionary)
{
var weather = data.get("weather")[0].get("icon");
var temperature = data.get("main").get("temp");
dict["temp"] = temperature;
dict["code"] = weatherCodes.get(weather);
// Sys.println(dict);
Background.exit(dict);
}
else
{
// Sys.println("ERROR SIMULATED!");
Background.exit(400); // send some number to indicate an error
}
}
}
And then with my onBackgroundData in the app class:
function onBackgroundData(data) {
if (data != 400)
{
app_dict = data; // pass data to foreground
var now = Time.now().value();
//save coordinates if we got them
if (Activity.getActivityInfo().currentLocation != null)
{
Sys.println(Activity.getActivityInfo().currentLocation);
var lat = Activity.getActivityInfo().currentLocation.toDegrees()[0];
var lon = Activity.getActivityInfo().currentLocation.toDegrees()[1];
lat = Application.getApp().setProperty("lat", lat);
lon = Application.getApp().setProperty("lon", lon);
}
App.getApp().setProperty("weatherCode", app_dict["code"]);
App.getApp().setProperty("temperature", app_dict["temp"]);
App.getApp().setProperty("timestamp", now);
Ui.requestUpdate();
}
else
//we got some error
{
//see if we can retrieve the previously stored value, otherwise fill in an empty string
var prevCode = App.getApp().getProperty("weatherCode");
app_dict["code"] = prevCode == null ? prevCode : null;
var prevTemp = App.getApp().getProperty("temperature");
app_dict["temp"] = prevTemp == null ? prevTemp : null;
}
}
Lastly, I check in my view initialize() code (which I assume is run each time the user checks the watch face app after closing another screen on their watch) whether the latest timestamp is "too new" for a background event request. If not,
const MIN_TIME = 900; // 15 min
function initialize() {
WatchFace.initialize();
var now = Time.now().value();
var timeLastGPS = App.getApp().getProperty("timestamp"); // get timestamp of the last time we saved
if (timeLastGPS != null)
{
if (now - timeLastGPS < MIN_TIME) // load recent GPS data if it hasn't been more than X min
{
if (App.getApp().getProperty("temperature") != null)
{
app_dict["temp"] = App.getApp().getProperty("temperature");
app_dict["code"] = App.getApp().getProperty("weatherCode");
}
}
else
{
// fire up GPS event
var FIVE_MINUTES = new Time.Duration(5 * 60);
var lastTime = Background.getLastTemporalEventTime();
if (lastTime != null) {
// Events scheduled for a time in the past trigger immediately
var nextTime = lastTime.add(FIVE_MINUTES);
Background.registerForTemporalEvent(nextTime);
} else {
Background.registerForTemporalEvent(Time.now());
}
}
}
}
And I use check if app_dict["code"] != null to make changes in the onUpdate(dc) which seems to work with no problems. Also, I thought the watch needs to be connected to WiFi in order to make a request to the API, but it seems like a watch-phone connection also works.