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!

  • I'm pretty sure that was posted someplace in this thread (using Activity.Info), but an additional note. Make sure you do a null check on it. Last time I checked, it can be null on a fenix 5x (and maybe others), and in that case, I fall through and still use getHeartRateHistory().

    And depending on what else your WF does at 1hz, you may want to make the screen update a bit "smarter" (that's discussed in this thread)
  • I'm pretty sure that was posted someplace in this thread (using Activity.Info), but an additional note. Make sure you do a null check on it. Last time I checked, it can be null on a fenix 5x (and maybe others), and in that case, I fall through and still use getHeartRateHistory().

    And depending on what else your WF does at 1hz, you may want to make the screen update a bit "smarter" (that's discussed in this thread)


    Thanks for keeping up to date on this. It looks like the link to your sample in the original post is no longer working. Would you mind updating it? I'm very curious to take a look. Thanks!
  • It seems that something broke in the forum as far as .zip files. If you PM your email address to me, I'll send the same to you.. I'll also try posting it again here.
  • 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.


    I am about to test 1Hz mode on my new analog watchface. If I understand this thread (and the enormous amount of work put into it! thank you!), it appears that I can legitimately "override" the power budget by using a delegate, correct? If this is correct, are there any negative aspects to this aside from a little extra battery drain?
  • it appears that I can legitimately "override" the power budget by using a delegate, correct? If this is correct, are there any negative aspects to this aside from a little extra battery drain?

    No this is not correct, there is no way to override the budget.

    The delegate is just to be able to trap and log when budget exceeded exception happens, and then you can take appropriate action to disable further attempts to perform 1Hz.
  • No this is not correct, there is no way to override the budget.

    The delegate is just to be able to trap and log when budget exceeded exception happens, and then you can take appropriate action to disable further attempts to perform 1Hz.


    Thank you for the note.
  • No this is not correct, there is no way to override the budget.

    The delegate is just to be able to trap and log when budget exceeded exception happens, and then you can take appropriate action to disable further attempts to perform 1Hz.


    I just ran a test on my onUpdate function. Captured time at beginning and at end. The results are attached (about 16 ms) for full update in "High Power" mode (second hand being redrawn along with full screen each second). It appears I could run 1Hz with the now issue since the average per run is less than 30ms. Am I understanding the power budget correctly, or am I off my rocker :)
  • Staying within the power budget is the trickiest part of 1hz, and analog WFs are trickier than digital in most cases. Be sure to check out the analog sample in the SDK
  • Staying within the power budget is the trickiest part of 1hz, and analog WFs are trickier than digital in most cases. Be sure to check out the analog sample in the SDK


    Thank you, again! I had referred to this example often, and I missed that it included 1Hz support.
  • For the data you posted (the 16 ms) you're timing how long onUpdate take in the sim. That part will vary based on the machine you're running on. an i3 could take more than an i7 for example (I've never tried, so just a guess). When you do things in onPartialUpdate(), it's what you can expect on the watch itself. Even given the sample code I posted, in the sim, it runs fine if you have an f5 as a target (that's what was out when I wrote it), but last time I tried it with a va3 as a target, it exceeded the power budget (not by a great deal, but 1hz will stop after a couple minutes). In the sample, I update hh:mm:ss at one hz and have the clipping region set for that part of the screen. The correction for the va3 would be to set the clip region for just ss and only update that part of the time.