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!

  • 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.


    This is very helpful. Now, I'll decide if it's worth the effort to try on this particular watchface or wait until I have a small region of screen to update.
  • jim_m_58, funny story (to me any way :) . I still wanted to learn how the 1Hz worked, so I followed your example in Analog. I added appropriate delegate, onPartial update, etc. I then put an if..else wrapper around my onUpdate that said if partialUpdatesAllowed, called onPartialUpdate. I duplicated the code in onPartialUpdate. Everything worked great! For about two minutes. lol. Obviously, I would not want to duplicate code for a real deployment, but for the exercise, it was interesting to see the results:

    Average execution time: 1154.680664
    Allowed execution time: 30.000000

    I learned a lot about 1Hz capabilities though! Thank you for the help and tutorial.
  • The "about two minutes" thing is what you'll see, as the power budget is the average over a minute (starting at the top of the minute). The amount used for a specific onUpdate can vary, especially in an analog WF, and that's the reason for the average. The number of "rows" for the clip region varies based on where the second hand is. Many rows at 6 and 12, fewer rows at 3 and 9, and the rows are important when updating the screen.

    In your case, 1hz was using more than 1 sec each onUpdate. I think that may be a record! :)

    Setting a clip region is critical for 1hz, as you want to define only the part of the screen you want to change. With no clip region, you'll exceed the budget all the time.
  • The "about two minutes" thing is what you'll see, as the power budget is the average over a minute (starting at the top of the minute). The amount used for a specific onUpdate can vary, especially in an analog WF, and that's the reason for the average. The number of "rows" for the clip region varies based on where the second hand is. Many rows at 6 and 12, fewer rows at 3 and 9, and the rows are important when updating the screen.

    In your case, 1hz was using more than 1 sec each onUpdate. I think that may be a record! :)

    Setting a clip region is critical for 1hz, as you want to define only the part of the screen you want to change. With no clip region, you'll exceed the budget all the time.


    Based on what I've learned (from you and another), I tried minimizing resources used in the onUpdate. With everything I have going on, trying to get that second hand moved under budget may not be feasible. I'd likely have to minimize its size and move other graphics outside of its radius, which would diminish the look. Any high level ideas of what I might consider beyond that? (I don't mind to dig and research, but the idea flow is empty lol...may just have a nice watch with high-power seconds only). Perhaps instead of worrying about Buffered Bitmap, which only helps on a few devices, a clip region approach?
  • Look at using buffered bitmaps.
  • I really do hate to bother you once again, but a final question before I go back into the dev cave. I only use the 15 colors available to most watches...the exact hex. If I made a bit map of the watchfaces and loaded them, I know it would use more storage memory, but how does redrawing that (with numbers, hash marks) compare to having the processor generate those marks?
  • Look at using buffered bitmaps.


    Hi Jim_m_58. I have spent a few days diving in to both 1Hz (buffered bitmaps and clip areas) and "refactoring" fonts by changing them to images, etc., for smooth hands, etc. If I understand correctly, these two techniques do not play well together. If I use fonts for images, watchhands, etc., then I have to rewrite them each time, because buffered bitmaps only permit aliased fonts. This redrawing ends up extending past the 30ms budget of 1Hz partial update operations. Am I understanding this correctly? Just trying to learn the boundaries :)
  • You're into stuff I've never tried or even really looked at. One thing that I do know, and may come into play is you don't want to load any resources in onPartialUpdate.
  • You're into stuff I've never tried or even really looked at. One thing that I do know, and may come into play is you don't want to load any resources in onPartialUpdate.


    Thank you, Jim
  • Former Member
    Former Member over 7 years ago
    You can draw anti-aliased fonts into a buffered bitmap if it does not have a reduced color palette. Buffered Bitmaps are not going to be useful for your moving objects. They are helpful when you have something slow to draw in the background of your display. For instance, text is slow to draw, and bitmaps are much faster. By creating a bitmap and drawing something like the date into it, you can redraw that behind a moving analog hand every second much more cheaply than if you had to blank and redraw the text from scratch.