Question about custom watchface battery consumption

Hi all,

I'm pretty worried about the battery of my VivoActive 4 (lasting about 3 days at most, without doing activities). Yes, I've done some things to alleviate that (no notifications, no SpO2, low brightness), and I wanted to create the simplest possible watchface, showing only hours and minutes, and with no partial updates.

My question is, even with this very basic IQ watchface, ¿will battery consumption be worse than default garmin ones? This is the furthest I've managed to go:

Watchface profiler

This is a profile of 20secs of the watchface, between a minute (e.g. the 20 secs are within the same minute)

And this is some of the code (but only drawing hours and minutes, no date). As you can see, I've commented out a version with WatchUi views, founding it spending about 10% more time on the whole OnUpdate.

    
import Toybox.Graphics;
import Toybox.WatchUi;
import Toybox.Time.Gregorian;

class ShyView extends WatchUi.WatchFace {

    private var _timeFont as FontResource?;
    private var _dateFont as FontResource?;
    private var _height;
    private var _width;
    private var _centerX;
    private var _centerY;
    private var _dateAlreadyCalculated;
    private var _stringHours;
    private var _stringMinutes;
    private var _stringTime;
    private var _stringDateTop;
    private var _stringDateBottom;
    hidden var _tvTime;
    hidden var _tvDateTop;
    hidden var _tvDateBottom;

    function initialize() {
        WatchFace.initialize();
        _dateAlreadyCalculated = false;

        // Load resources
        _timeFont = WatchUi.loadResource($.Rez.Fonts.id_font_fjalla_large) as FontResource;
        _dateFont = WatchUi.loadResource($.Rez.Fonts.id_font_fjalla_small) as FontResource;
    }

    function onSettingsChanged() {
        // No settings
    }

    function onLayout(dc) {
        setLayout(Rez.Layouts.WatchFace(dc));

        // Dimensions
        _width = dc.getWidth();
        _height = dc.getHeight();
        _centerX = _width / 2;
        _centerY = _height / 2;
    }
 /*
    function onShow() {
        _tvTime = new WatchUi.Text({
            :text=>_stringTime,
            :color=>Graphics.COLOR_WHITE,
            :font=>_timeFont,
            :locX =>WatchUi.LAYOUT_HALIGN_CENTER,
            :locY=>WatchUi.LAYOUT_VALIGN_CENTER
        });
        _tvDateTop = new WatchUi.Text({
            :text=>_stringDateTop,
            :color=>Graphics.COLOR_WHITE,
            :font=>_dateFont,
            :locX =>WatchUi.LAYOUT_HALIGN_CENTER,
            :locY=>40
        });
        _tvDateBottom = new WatchUi.Text({
            :text=>_stringDateBottom,
            :color=>Graphics.COLOR_WHITE,
            :font=>_dateFont,
            :locX =>WatchUi.LAYOUT_HALIGN_CENTER,
            :locY=>_height - 40
        });
    }
    */


    // Update the view
    public function onUpdate(dc as Dc) as Void {
        // Call the parent onUpdate function to redraw the layout
        //View.onUpdate(dc);

        // Same color for all
        dc.setColor(Graphics.COLOR_LT_GRAY, Graphics.COLOR_BLACK);
        dc.clear();

        // Draw the UI
        var clockTime = System.getClockTime();
        calculateTime(clockTime);
        drawHoursMinutes(dc);
        calculateDate(clockTime);
        drawDate(dc);     
    }

    private function drawHoursMinutes(dc) {
        //_tvTime.setText(_stringTime);
        //_tvTime.draw(dc);

        // Draw hours
        //dc.setColor(Graphics.COLOR_RED, Graphics.COLOR_TRANSPARENT);
        dc.drawText(
            _centerX - 4,
            _centerY - 12,
            _timeFont,
            _stringHours,
            Graphics.TEXT_JUSTIFY_RIGHT | Graphics.TEXT_JUSTIFY_VCENTER
        );

        // Draw minutes
        dc.drawText(
            _centerX + 4,
            _centerY - 12,
            _timeFont,
            _stringMinutes,
            Graphics.TEXT_JUSTIFY_LEFT | Graphics.TEXT_JUSTIFY_VCENTER
        );
        
    }

    private function drawDate(dc) {
        //dc.setColor(Graphics.COLOR_LT_GRAY, Graphics.COLOR_TRANSPARENT);

        //_tvDateTop.setText(_stringDateTop);
        //_tvDateBottom.setText(_stringDateBottom);
        //_tvDateTop.draw(dc);
        //_tvDateBottom.draw(dc);

        // Top part of the date
        dc.drawText(
            _centerX,
            24,
            _dateFont,
            _stringDateTop,
            Graphics.TEXT_JUSTIFY_CENTER | Graphics.TEXT_JUSTIFY_VCENTER
        );

        dc.drawText(
            _centerX,
            _height - 32,
            _dateFont,
            _stringDateBottom,
            Graphics.TEXT_JUSTIFY_CENTER | Graphics.TEXT_JUSTIFY_VCENTER
        );
        
    }

    private function calculateTime(clockTime) {
        var hours = clockTime.hour;
        var minutes = clockTime.min;
        if (clockTime.min < 11) {
            minutes = clockTime.min.format("%02d");
        }
        _stringHours = hours;
        _stringMinutes = minutes;
        _stringTime = hours + "" + minutes;
    }

    private function calculateDate(clockTime) {
        if (!_dateAlreadyCalculated || clockTime.min == 1) {
            var now = Time.now();
            var date = Gregorian.info(now, Time.FORMAT_MEDIUM);
            _stringDateTop = Lang.format("$1$", [date.day_of_week]);
            _stringDateTop = _stringDateTop.toUpper();
            _stringDateBottom = Lang.format("$1$ $2$", [date.day, date.month]);
            _stringDateBottom = _stringDateBottom.toUpper();

            _dateAlreadyCalculated = true;
        }
    }
}

    
  • In the sim, by default, the WF is in high power mode, where onUpdate() is called every second, but on a real device, the majority of the time, the WF is in low power (onUpdate() is called once a minute.  In the sim, you can switch to low power with "Settings>Low Power Mode".

    You can tell the state the WF is in based on which was called last - onEnterSleep or onExitSleep.

    On a real device, the WF drops out of low power for about 10 seconds after a gesture/tap.

  • thanks for that jim, very appreciated :) I already knew, but thanks nevertheless :) Slight smile

    my question is: is there a way that my custom watchface can be more battery friendly than predefined ones? Right now, I'm trying to do my own measurements.

    is there a way that I can profile/plot the battery consumption history? Can't find such info on the watch nor in the app

    thanks again!

  • Charge watch to 100%, run a native WF for a couple days, then do the same with yours and compare the battery drop. 

    Based on the code you posted, I'd expect things to be very similar.  The complexity of the native WF could have an impact though.

  • ok, will do that, thanks

    Is there a way to save the automatic call to `getTextDimensions()`? Can I use a font with the same width and height for all chars, so the font measurement involved in `dc.DrawText` is not needed? Can't find something in the docs

    Is there a way to have bigger system fonts? sizes included aren't as big as I want

  • update: about not calculating text dimensions, I've found that drawing some bitmaps is cheaper than using a font.

    about my bad battery usage: I rebooted the watch, and it's way better now. 

    Thanks for all