Variables value gets lost in Watchface

Hello everybody,

I added a function to my watchface which isn't working but I really don't have a clue why.

The goal is simply to sum up the min and hours moved on a day. To a certain extend that works but every once in a while he resets and I don't know why. I never reached vaules over 40 min before it got reset for no reason I understand.

Anybody aware of the fault I made?

The view.mc

using Toybox.Lang as Lang;
using Toybox.System as Sys;
import Toybox.WatchUi;
using Toybox.Time.Gregorian as Date;
using Toybox.Application as App;
using Toybox.ActivityMonitor as Mon;


class Last_MoveView extends WatchUi.WatchFace {
    var stepsolds = 0;
    
    var summoved = 0;
    var hoursmoved=0;
    var minmoved=0;
    var minalt = 0;

    function initialize() {
        WatchFace.initialize();
    }

    // Load your resources here
    function onLayout(dc) {
        setLayout(Rez.Layouts.WatchFace(dc));
    }

    // Called when this View is brought to the foreground. Restore
    // the state of this View and prepare it to be shown. This includes
    // loading resources into memory.
    function onShow() {
    }

    // Update the view
    function onUpdate(dc) {
        setsummoved();

        View.onUpdate(dc);
    }

    // Called when this View is removed from the screen. Save the
    // state of this View here. This includes freeing resources from
    // memory.
    function onHide() {
    }

    // The user has just looked at their watch. Timers and animations may be started here.
    function onExitSleep() {
    }

    // Terminate any active timers and prepare for slow updates.
    function onEnterSleep() {
    }

the function:

function setsummoved() {

        var zeit = Sys.getClockTime();
        var stepnews = Mon.getInfo().steps;
        //stepnews =50;
        //summoved =100;
        if (zeit.hour>5) {        //datealt
            if (stepnews>stepsolds+20){      //and (now.min>minalt)
                if (zeit.min>minalt) {
                    summoved=summoved+1;
                    if (summoved>60){
                        hoursmoved=(summoved/60); //summoved % 60;
                        minmoved = summoved % 60;//summoved - (hoursmoved*60);
                    } else {
                        hoursmoved=0;
                        minmoved = summoved;
                    }
                }
            }
            var timeStrings = Lang.format("$1$:$2$", [hoursmoved, minmoved.format("%02d")]);
            var view = View.findDrawableById("summovedDisplay");   //Anzeige Mitte Z3  Uhrzeit der letzten Bewegung 55 85
            view.setText(timeStrings); 
            minalt=zeit.min;
            stepsolds=stepnews;
        }else{
            summoved=null;
            hoursmoved=null;
            minmoved=null;
        }

    }

The Layout:

<layout id="WatchFace">
    <label id="summovedDisplay"    x="55%"     y="85%"     font="Graphics.FONT_XTINY"              justification="Graphics.TEXT_JUSTIFY_CENTER" />
</layout>

  • Interesting point - and a good point for the future but for the moment I really want to make it work first and don't care about my battery.

  • With the println calls in your code, if you do a sideload and create a log file on the watch to see what's happening there.  The file would be in garmin\apps\logs and named <appname>.txt

  • Ahh cool I didn't knew that one. Cause in deed the problem only aroses on the watch - on the simulator everything works fine. 

  • Hi Jim,

    well I finally found the two resons my watchface wasn't working.

    • A lot of the functions I was using worked with steps in if statements. I mean I was reading them up to 10 times a minute but that doesn't mean that the watch is really supplying new step countings. So he reads the stepsquantity and was writing that into the variable but sometimes Mon.getinfo had no new quantity also it should have. => So I changed to a check every 3 minutes and get it a third to get the steps per min.
                      var stepnewotm = Mon.getInfo().steps;
    • The second problem I need you help for:

      I found out that the data I was storing are max local but I need public available data.

      The way I proceeded
            In the initialize function I had a
                    App.Storage.setValue("stepssaved", steps);

           and in the function I had a
                        if (App.Storage.getValue("stepssaved")!=null){
                            steps=App.Storage.getValue("stepssaved");
                        }else{
                            steps=0;
                        }
    Hope you can help. 

    Regards Marcus
  • 1. Write whole app that run well in sim

    2. kill app and run again - you will see what is wrong and you will know which variables should be saved in storage and

    - save members in App.onStop - only once last value

    - read members in App.onStart - only once last saved value

    3. wf most time spend in low power (power budget) so you can't do any expensive things (storage/resource operation are forbidden).

    4. if you need something "in time" you need save also timestamps - it means save in storage all necessary data which are needed to restore state

  • And how can I save?

    I mean it doesn't seem to save the data I try to store.via

    App.Storage.setValue("stepssaved"steps);

    Has anybody a example on github or can write a few lines?

    Until now I haven't found a watchface storing data.

    What do you mean by save members App.on Stop?

    I found that here as well but also without an examble.

    Data Field variables lost when you Resume Later - Discussion - Connect IQ - Garmin Forums

  • yes save=storage.setValue()

    App means your application class

    https://developer.garmin.com/connect-iq/api-docs/Toybox/Application/AppBase.html

    class AppLifeCycleView extends WatchUi.WatchFace
    {
        var storagevar;
        
    }
    
    class AppLifeCycle extends Application.AppBase {
        // initialize the AppBase class
        var view;
        
        function initialize() {
            AppBase.initialize();
        }
        // onStart() is called on application start up
        function onStart(state) {
        }
        // onStop() is called when your application is exiting
        function onStop(state) {
            Storage.setValue("key", view.storagevar);
        }
        // Return the initial view of your application here
        function getInitialView() {
            view = new AppLifeCycleView();
            view.storagevar = Storage.getValue("key");
            return [view];
        }
    }

  • Hey _psx,

    thanks a lot for the response.

    I'm really happy to get closer to the solution altough it's not yet working out.

    Starting the simulation now results in a white screen, or shows the garmin triangular. Any idea why? It worked before.

    This is my Appmc:

    import Toybox.Application;
    import Toybox.Lang;
    import Toybox.WatchUi;
    
    class movergraApp extends Application.AppBase {
    var view;
        function initialize() {
            AppBase.initialize();
        }
    
        // onStop() is called when your application is exiting
        function onStop(state) {
            AppBase.Storage.setValue("steps", view.steps);
            //AppBase.Storage.setValue("uhrzeitarray", view.uhrzeitarray);
        }
        function onStart(state) {
        }
    
        function getInitialView(){
            view = new movergraView();
            view.steps = AppBase.Storage.getValue(steps);
            //view.uhrzeitarray = AppBase.Storage.getValue(uhrzeitarray);
            return [view];
            //return [uhrzeitarray];
        }
        /*// onStart() is called on application start up
        function onStart(state as Dictionary?) as Void {
        }
    
        // onStop() is called when your application is exiting
        function onStop(state as Dictionary?) as Void {
        }
    
        // Return the initial view of your application here
        function getInitialView() as Array<Views or InputDelegates>? {
            return [ new movergraView() ] as Array<Views or InputDelegates>;
        }*/
    
    }
    
    function getApp() as movergraApp {
        return Application.getApp() as movergraApp;
    }

    And that's the beginning of my Viewfile:

    using Toybox.Lang as Lang;
    using Toybox.System as Sys;
    import Toybox.WatchUi;
    
    using Toybox.Time.Gregorian as Date;
    using Toybox.Application as App;
    using Toybox.ActivityMonitor as Mon;
    using Toybox.Timer;
    using Toybox.Time as Time;
    using Toybox.UserProfile as UserProfile;
    using Toybox.Graphics as Gfx;
    
    class movergraView extends WatchUi.WatchFace {
    
        public var stepsinper = 0;
        public var stepotm =  Mon.getInfo().steps;
        public var firstrun = false;
        public var steps = [0, 0, 0, 0, 0, 0,
                            0, 0, 0, 0, 0, 0,
                            0, 0, 0, 0, 0, 0,
                            0, 0, 0, 0, 0, 0,
                            0, 0, 0, 0, 0, 0,
                            0, 0, 0, 0, 0, 0,];
        public var uhrzeitarray = ["init", "init", "init", "init", "init"];
    
        function initialize() {
            WatchFace.initialize();
        }

    The initial values of my arrays are later deleted and extended:

    steps.remove(steps[0]);
    steps.add(stepsinper);

  • Neither did this App.mc work - Same Garmin triangle:
    Bottom of the Garmin page:
    import Toybox.Application;
    import Toybox.Lang;
    import Toybox.WatchUi;
    
    class movergraApp extends Application.AppBase {
    var view;
        function initialize() {
            AppBase.initialize();
        }
    
        // onStop() is called when your application is exiting
        function onStop(state) {
            //AppBase.Storage.setValue("steps", view.steps);
            //AppBase.Storage.setValue("steps", view.steps);
    
            var app=Application.getApp();
            app.setProperty("steps", steps);
            //AppBase.Storage.setValue("uhrzeitarray", view.uhrzeitarray);
        }
        function onStart(state) {
        }
    
        function getInitialView(){
            var app=Application.getApp();
            var steps = app.getProperty("steps");
            //view = new movergraView();
            //view.steps = AppBase.Storage.getValue(steps);
            //view.uhrzeitarray = AppBase.Storage.getValue(uhrzeitarray);
            return [steps];
            //return [uhrzeitarray];
        }
        /*// onStart() is called on application start up
        function onStart(state as Dictionary?) as Void {
        }
    
        // onStop() is called when your application is exiting
        function onStop(state as Dictionary?) as Void {
        }
    
        // Return the initial view of your application here
        function getInitialView() as Array<Views or InputDelegates>? {
            return [ new movergraView() ] as Array<Views or InputDelegates>;
        }*/
    
    }
    
    function getApp() as movergraApp {
        return Application.getApp() as movergraApp;
    }