How to enable an "always-on" mode for Venu/AMOLED

I am trying to do a basic Venu watch face where I'm just printing a large font digital time while in "high power" mode and then printing a very small font time when the device enters sleep. The goal is to get an "always-on" functionality working.

The CIQ3.1 release notes say this:

"Always On watch faces behave differently from MIP to AMOLED. With MIP screens, you can use View.onPartialUpdate to update a portion of the screen every second. With AMOLED screen, this is no longer allowed. Instead, when WatchUi.onEnterSleep is called, you are allowed to render a watch face that must obey the rules of the AMOLED burn-in
protector:

  • No more than 10% screen pixels can be on
  • No pixel can be on longer than 3 mins

Ways you can prevent burn in are by drawing the time with a thin font, shifting the time every minute as not to repeatedly leave the same pixels on, and not having static tick marks that leave the same pixels on.

Note that watch faces can detect whether a product has screen protection enforced by checking the value of DeviceSettings.requiresBurnInProtection."

I have used the OnEnterSleep method to set a var called lowPower (and the OnExitSleep to clear it) and then I do a forced update via WatchUi.requestUpdate(). The update method then paints the screen black and draws the text. The text is very small and clearly less than 10% of the pixels. I also implemented a basic rotational algorithm where the text is shifted around the screen automatically on every update, as per the requirements above. The text never overlaps with itself so I'm pretty sure I'm meeting all of the burn-in requirements.

In the simulator I see everything working correctly, and I can toggle Low Power Mode and everything appears as I want it to. I also don't get the heatmap warning indicator, so again I'm pretty sure I'm meeting all of the requirements. But when I put the .prg on my watch and try to run it, the watch always turns the display off. I see the high power mode, and then I see the small text when it goes to sleep, but then the display immediately turns off. I'm not sure what I am doing wrong.

  • So after further investigation I think my design is actually working correctly! I think the problem is that when I place the watch on a table, it automatically shuts the screen fully off. I can't get it to work unless I'm wearing it. It must be using heart rate or something because I can also make it work by putting my thumb firmly over the heart rate sensor.

  • Hi, I'm looking at starting creating a watch face, would you be able to help share your code so I can see how to configure always on?

  • Here's the view for a really simple on.  If in High power, it displays the seconds.  If in low power, it moves the time around on a venu.

    using Toybox.WatchUi;
    using Toybox.Graphics as Gfx;
    using Toybox.System as Sys;
    using Toybox.Time.Gregorian as Calendar;
    
    class AlwaysView extends WatchUi.WatchFace {
    
    	var width, height;
    	var timeF=Gfx.FONT_NUMBER_MEDIUM;
    	var timeFH=0;
    	var inLowPower=false;
    	var canBurnIn=false;
    	var upTop=true;
    	
        function initialize() {
            WatchFace.initialize();
            //check if burn in protection needed
            var sSettings=Sys.getDeviceSettings();
            //first check if the setting is availe on the current device
            if(sSettings has :requiresBurnInProtection) {
            	//get the state of the setting      
            	canBurnIn=sSettings.requiresBurnInProtection;        	
            }        
        }
    
        // Load your resources here
        function onLayout(dc) {
    		width=dc.getWidth();
    		height=dc.getHeight();
    		timeFH=dc.getFontHeight(timeF);
    	}
    
        function onShow() {
        }
    
        function onUpdate(dc) {
       		dc.setColor(Gfx.COLOR_BLACK,Gfx.COLOR_BLACK);
       		dc.clear();
       		dc.setColor(Gfx.COLOR_WHITE,Gfx.COLOR_TRANSPARENT);
    
    		//do the common date/time code
            var now = Time.now();
            var clockTime = Calendar.info(now, Time.FORMAT_MEDIUM);
            var hour=clockTime.hour;      
            if(!Sys.getDeviceSettings().is24Hour) {
    			hour = hour % 12;
                hour = (hour == 0) ? 12 : hour;
            }        
            var timeString=hour+":"+clockTime.min.format("%02d");
            var dateString=clockTime.month+" "+clockTime.day;
            
            //setop for the display of the date and time
            var y=height/2;
    		if(inLowPower) {
    			if(canBurnIn) {
    				//move things on the venu
    				y=(upTop) ? height*.25 : height*.75;
    				upTop=!upTop;
    			}
    		} else {
    			//add seconds if not in low power (sleep) mode
    			timeString=timeString+":"+clockTime.sec.format("%02d");
    		}
    		//actually display date and time
    		dc.drawText(width/2,y,timeF,timeString,Gfx.TEXT_JUSTIFY_CENTER|Gfx.TEXT_JUSTIFY_VCENTER);
    		dc.drawText(width/2,y+timeFH/2,Gfx.FONT_TINY,dateString,Gfx.TEXT_JUSTIFY_CENTER|Gfx.TEXT_JUSTIFY_VCENTER);
        }
    
        function onHide() {
        }
        
        function onExitSleep() {
            inLowPower=false;
        	WatchUi.requestUpdate(); 
        }
    
        function onEnterSleep() {
        	inLowPower=true;
        	WatchUi.requestUpdate(); 
        }
    }
    

  • Thanks for posting. Mine is essentially the same thing. I also change fonts to a small/skinny font in low power mode, because you need to use <= 10% of the pixels, so having large fonts makes it hard to satisfy the always-on requirements. If you don't satisfy the requirements, the screen will just automatically turn off. So if you are seeing your screen turn off, try reducing the pixels in use, and make sure you are rotating the text enough so that you are not overlapping pixels. Also like I said, if you have a real device, you have to be actually wearing it otherwise the screen will shut off no matter what you do.

  • The fonts I use in the sample work fine.  You can see where you're at viewing the heatmap in the sim and doing the 24 hour simulation.  There are things you can do to be withing limits without moving things around.   in Simple Lean by way of app settings, you can see a method where the time doesn't move, but is dimmer (I vary what pixels are on)

    With a real device, it uses OHR to see if you're wearing the watch.  If not the screen goes blank

  • Hello Jim, i just tried your example above and it does not work, screen always turn to black-blank...also my implementation works fine in 24-hour simulation but no success on the watch.

    Any suggestions? Or does it only work after uploading in store?

  • Do you have always on enabled on the watch?  You also must be wearing the watch.  If there's no HR detected, it will blank.

  • Ok, i have tried to change it to always on, and back, after several times it started working! Thanks.

  • Jim - Any idea how Garmin and some CIQ developers have gotten analog hands (with an arbor) to work?  I'm getting a heat map burn in warning on the Hour hand and on the Arbor - which isn't a surprise. 

    When I take a photo of the Venu watch face with a Garmin always on/low power face running (with white hands) it looks solid (as far as my feable eyes can see) but I imagine pixels are being shifted each minute or there's some form of interlacing going on.  I cant envision what the code for that would look like.  Do you know what technique is being used?

    Has anyone posted an example of low power analog hands? - JA

    PS I just bailed on the Fenix 6 Pro in favor of a Venu (hoping I can get code to work on the Venu!)

  • Based on 's example, you need to shift the hands center point every second to prevent a single pixel from being lit on the same position for more than 3 seconds (burn-in protection). However, I know this is hard to achieve on analog hands as I've been trying this for a few days now and still couldn't get it working. I started to try shifting the centre point a bit to the sides as well (together with up/down) and got to a point where I can get the analog hands for 5 minutes on the heat map simulator until a couple of pixels reach the burn-in limit (instead of most of the hour hand at 3 minutes). 

     I'll give it a try a bit more with different options, but in case I can't get it working, the solution would be to use some kind of interlacing on the drawPolygon, but no clue yet on how to do it. Any ideas, ?