Why does this work in the Simulator but not on the watch?

I have a Vivoactive 4S and am using Connect IQ v3.1.9 on a Windows 10 laptop.  I want to display a message on the phone every alternate evening to remind me to take a tablet (a pill not an iPad lol!).  I am using a version of the Analog clockface example that came with v3.1.9 and have modified (amongst other things) the drawDateString function to do what I want.  drawDateString is called as part of the onUpdate function and the relevant code is:-

    var takeTablet = false;         //  Class declarations
    var tabletSeconds = 59;         //     ditto

		if (info.hour == 5 && info.min == 0 && info.sec <= tabletSeconds) {
			takeTablet = ! takeTablet;
			tabletSeconds = info.sec;
			System.print("tabletSeconds = ");
			System.print(tabletSeconds);
			System.print(" - takeTablet = ");
			System.println(takeTablet);
		}
		if (takeTablet && (info.hour > 21 || info.hour < 5)) {
	        dc.drawText(x, y+24, datefont, "Take Tablet", Graphics.TEXT_JUSTIFY_CENTER);
		}

This all works fine in the simulator with Low Power Mode set but not at all on the watch itself.  As far as I can see the 'takeTablet' boolean is never changed.  I don't think that my code is at fault (hubris not being a fault of mine!!!) because it works properly in the Simulator so what is it that is different on the watch?  And, more importantly, what should I do to get it to work?

  • When you're in low power mode, onUpdate is only called once a minute, at seconds = 0, otherwise, it's called every second (for 10 seconds on a real device, continually in the sim)

    Also, unless you are saving takeTablet in something like Application.Storage, it's going to be false whenever the WF starts, say after going to any screen other than the watchface.

  • Thanks for a very quick reply.  Part of the reason that I used tabletSeconds, initially set to 59 was to cancel out (at least initially) any potential variations of the seconds, in part on the assumption that there would be times when onUpdate was going to run more frequently than once a minute.

    The fact that getTablet would revert to false on any WF change I hadn't realised and is almost certainly the reason that it's not working.  Just for clarity, I tend to switch to the module carousel to check battery level and also swipe up and down to check various stats.  Do each/either of those restart the watchface?  But, many thanks for the pointer.

  • Moving to the widget loop will cause takeTablet to reset to false, as will going to any other screen, and possibly when you get a notification of any sort  You probably not only want to save that, but a time stamp for when you last changed it.

  • OK.  I'm just investigating Application.Storage (based on an answer of yours some 2 years ago - thanks for that, also).  At this stage I'm not quite clear as to where to put the setValue initialisation.  Does it go into the initialise function of the AnalogView Class or into the AnalogWatch class which is what initialises the AnalogView object.  Basically, does the initialise function within AnalogView fire just the once when the app is first started or does it fire every time the watchface changes screen?  Obviously I just need to try it both ways but, whilst it might work quickly in the simulator, it is going to take the best part of 48 hours to know whether it has worked on the watch.

  • You do the setValue when the value changes.

    The getValue(), initializes is good, where if the keys are null assume you haven't changed it yet.  "No date or value"

  • I don't quite understand that.  I need to set getTablet to an initial value, either true or false depending on the day I restart the app.  It is that initial setting that I'm unsure about.  Do I need to do that in whatever initialises the AnalogView object or do I do it within the initialise function within AnalogView - is the AnalogView initialis function called each time the watchface is changed or only when the app is restarted?

  • If you know that on Nov 6th you need to take a tablet, you can hard code for that as well as a timestamp, but  when you do

    takeTablet = ! takeTablet;

    do something like

    Application.Storage.setValue("take",takeTablet);

    Application.Storage.setValue("lasttime",Time.new().value());

    if it's not Nov 6th, you would read the two values in initialize() with something like

    take=Application.Storage.getValue("take");

    lastTime=Application.Storage.getValue("lasttime);

    You would then use lastTime to figure out the next time the message should display.  The way I'm storing lasttime is tyhe # of seconds since Jan 1st, 1970 UTC (commonly called "Unix time" and it's easy to do math with it.)

    var now=Time.now().value();

    if(now-lastTime> 48*60*60) {

    ....

    }

    if more than 48 hours have passed, set the flag

  • Here's a bit more (ignoring the Nov 6th thing)

    in initialize, when you getValue() for "lasttime, what you get back will be null (lastTime variable)

    then you could do something like (untested code so I may have missed something)

    if ((lastTime==null || now-lastTime>= 48*60*60) && info.hour == 5 && info.min == 0 && info.sec <= tabletSeconds)) {
    takeTablet = ! takeTablet;

    Application.Storage.setValue("take",takeTablet);

    Application.Storage.setValue("lasttime",Time.new().value());

    }

    so, if (there is no last time, or it's been 48 hours or more) and (if 5:00) then toggle takeTablet and save current state.  You might want to force the timestamp to be today at 5:00

  • Thanks (again).  On reflection, I think that the tabletSeconds variable might be overkill (or worse).  It is (just) conceivable that I'd change the watchface more than once during the 0500 minute (unlikely, I agree as it is the middle of the night!) in which case the boolean would get changed twice. so I'll stick with info.sec == 0.  I've made the changes (based on your earlier email) and need to see what happens over the next 48 hours or so.