1hz Watch Faces - Q&A

I'm not sure if many folks have been trying the new "always active" watch faces in 2.3.x, but the 2.3.0.beta1 has been out for a month or so now. It's probably getting close to the 2.3.1 SDK release, and thought I'd start a Q&A for the feature, and start with some of what I've picked up in adapting a number of watch faces to use 1hz.

I'll be calling this feature "1hz", as that's what it really is - being able to change the screen on a watch face every second.
The most common thing will likely being the ability to display seconds all the time. One thing I'll note right off, is while you can update the screen every second, the underlying data still changes at the rate it did before, so if you use 1hz for the HR, you won't see the HR change every second.

A few basics.

  • 1hz is only available on some watches. The f5, f5s, f5x, 935, and Q5, but if you support a bunch of different watches, you can easily have it on some and not others.
  • 1hz happens by way of a new onPartialUpdate() for watch faces. onUpdate() is just like it was in the past, and when you are allowed to do a 1hz update, onPartialUpdated() is called. You don't have to change a thing in your code if you don't want to use 1hz.
  • onPartialUpdate() is VERY strict as to how long it can run. You have a "power budget", and the rule is that each minute, the average run time each second can't be greater than 30 milliseconds. This is the tricky part! :)



I started with the Analog Sample in the SDK, which does show what to do, but has some things you don't need to do for digital watch faces - there's no second hand passing over a bunch of different places on the screen with a digital one. The time is in a fixed spot on the screen in most cases.



Anyway's, the first thing I did was cut back to the basics of what was needed for a digital WF. I'll attached a project with a very basic 1hz watch face, but first a few notes about it.

  • vs1hzapp.mc shows how to use the delegate for the power exceeded deligate on watches that have 1hz, and still run on watches that don't do 1hz.
  • vs1hzview.mc I tried to comment as to where to do things, where not to do things, but took a simple approach where I don't just update the seconds at 1hz, I actually do hh:mm:ss. In real code, you likely have a separate space for seconds, and your setClip() will be adjusted for that. I just wanted to get the ball rolling here :). Also, note onEnterSleep() and the code there for 1hz...
  • In onPartialUpdate(), I have a comment about a simple change to make the watch face exceed the power budget, so you can see how that works



Ask questions, suggest other ideas, whatever. That's what this thread is for!

So here's the project! (it might be a bit different than the original one that was lost in the forum update) :

VS1hz-old.zip



NOTE: I should have mentioned this before, but you want to use a 2.3.x SDK for this project!

  • thanks again for the incredibly helpful info, Jim. we managed to get things working on the 935 (and presumably F5) for Big and Lean, just as you do in Simple Heart.

    one interesting benefit of the call to Activity.Info.currentHeartRate is that it is of benefit to other watch models with built in oHR. when those watches are in "wake mode," they have their HR updated frequently too (for the ten or so seconds before going back to sleep). that is an awesome benefit that means that users will get meaningful HR info when they gesture with their wrist to see what their current HR is. previously, even though i only appreciated it recently, the displayed HR info wasn't very useful unless one was really acting in a sedentary or constant activity level (where one's HR doesn't vary much).

    Aside: of course, with the Gestures bug in the current F5/935 firmware, i'm glad that we can, for these watches, simply display the HR at 1hz/ all the time!)
  • I have been using the onPartialUpdate to handle updating the second hand on a watchface. After about 2 minutes it stops calling the onPartialUpdate routine. Is this because the average compute time has exceeded limit ? The onHide, onEnterSleep or onPowerBudgetExceeded functions are never called. Has anyone seen this with the 2.3.1 SDK ? Is there anyway in the simulator to simulate the onPowerBudgetExceeded event ?
    Thanks
  • Yes, you are exceeding the power budget. It's the average over a full minute, which is why you see it after about 2 minutes. If the delegate for exceeding the budget isn't called, are you returning it in getInitialView()? (in the app class). See the sample I posted - how getInitialView checks to see if it's a device with onPartialUpdate(). The delegate is in the same source file as the view.

    In the sample I posted, if you look at onPartialUpdate(), there's a small change you can make there to see what happens with the power budget is exceeded.
  • Turns out i spoke too soon... Jan/we are encountering some really odd problems which i won't bore you with here (for now)...

    but i will toss this out here:

    how do 1hz and "wake" functionalities work with one another? am i correct in assuming that when in wake mode, everything updates including the partial update clips, at 1 hz?

    [short story of one of our oddities that motivates that question: i found that the steps counter on Big and Lean, which typically updates once a minute, would be updating a ~1hz sporadically (sometimes for several minutes at a time if i was walking around for several minutes)... i wonder if this oddity is the gestures/wake feature on the 935/Fenix 5 being really buggy/out of whack]
  • By wake mode, do you mean that you are out of low power mode? (onExitSleep was called). onUpdate() get's called every second then. I've heard of a problem on the f5 or 935 where the timeout after a gesture may not occur, but I know the beta (4.16) that was posted yesterday had something about the gesture, so it may be worth trying that.
  • By wake mode, do you mean that you are out of low power mode? (onExitSleep was called). onUpdate() get's called every second then. I've heard of a problem on the f5 or 935 where the timeout after a gesture may not occur, but I know the beta (4.16) that was posted yesterday had something about the gesture, so it may be worth trying that.


    This sounds correct. There was an issue with the timeout of LP mode after gesture. At least that is how we were able to reproduce it. I would say that giving that beta version a try would be a good start. If that does not fix it, then we definitely want to try and get a reproducible test case for it.

    Thanks,
    -Coleman
  • (couldn't post earlier, but let's hope this time it works)

    Coleman and Jim: you are correct: i am referring to the watch perhaps not returning to low power mode. (that's the only thing that would explain the rapidly updating step count)

    unfortunately, i am on the 935, so there is no comparable beta version to try out. hopefully, an official release will soon be coming to both the 935 and Fenix 5.
  • Thanks Jim! I had not returned the WatchFaceDelegate in the getInitialView().
  • I'm building a 1hz version of "Nyan Cat"

    Just had to post this to vent my frustrations.

    Average execution time: 30.437153
    Allowed execution time: 30.000000


    Missed it by 500 microseconds, Argh!!
  • I've been there Franco. You need to go through what you do based on onPartialUpdate() and look for any way to cut things down just a bit. That might mean just reducing the code just a bit, moving a calculation or two into onUpdate() and just using it, etc. Graphics are the hard on the budget, so you can look at the size and number of clipping reasons. If you mave more than one, maybe don't update them all each call, but do one every other call or only if what you're display changes or something.

    At one of the breakout session from the Summit, Brian talks about getting under the 30 ms limit and things to look at:
    https://developer.garmin.com/index.php/blog/post/connect-iq-developer-summit-2017-breakout-effective-monkey-c