Help on using ActivityMonitor::HeartRateSample

Former Member
Former Member
Ok .. before you laugh, I am a newbie at this. I design databases .. this is all new to me.

So here goes .. and a question ??

I would like to do the following .. spaghetti code.

At midnight .. display "--" on watch face
Upon first HR reading for the day .. display reading on watch face
On all subsequent readings ... check to see if it is lower then last reading. If it is .. display on watch face else discard it.

I understand that I can use HeartRateSample .. and I also need to store the HR value so I can check / compare it later.

So I have this .. and I know it is wrong. I do not have the device yet (building for a Vivoactive HR) which I will not have for a few weeks.

using Toybox.ActivityMonitor as Act;

var HRMin;
var HRInfo;

HRInfo = Act.getInfo();
HRMin = HRInfo.HeartRateSample;

dc.drawText(107,166,Gfx.FONT_SMALL, HRMin, Gfx.TEXT_JUSTIFY_RIGHT); // Draw Resting HR Value

I am wondering does HeartRateSample actually measure the HR value .. or does it just return the last HR value as read by the device ?

All it displays on the display is Class. I know nothing about classes. :(
  • I've never used this but it looks like you'll want to use ActMon.getHeartRateHistory() (with the parameters you want to use), which returns an iterator, which in turn you use to get a heartrate..

    And once you have a heartrate, it's a number. With a number, your call to dc.drawText() will work on the simulator but on on the watch (it's a bug in the simulator and shouldn't work there). The reason being is that drawText expects a string. So something like heartrate.toString() should be used.

    note: One thing I don't know is how to simulate heart rate history in the simulator. You can use Simulation>fit data for simulating live data for data fields, etc, but may not generate the history. Like I said, I never tried...
  • Former Member
    Former Member over 9 years ago
    I've never used this but it looks like you'll want to use ActMon.getHeartRateHistory() (with the parameters you want to use), which returns an iterator, which in turn you use to get a heartrate..

    And once you have a heartrate, it's a number. With a number, your call to dc.drawText() will work on the simulator but on on the watch (it's a bug in the simulator and shouldn't worth there). The reason being is that drawText expects a string. So something like heartrate.toString() should be used.


    Thank you ... I will look at this tomorrow when I have time.
  • Former Member
    Former Member over 9 years ago
    It was suggested to me to use HeartRateSample .. as "HeartRateIterator .. is only good up to the last power cycle, so if you had to restart your watch for some reason or the watch crashes, you'd lose data prior to the reboot"

    I am far from understanding how to implement it, but in time I will get there and do thank the developer community here for all their help so far. Who knows .. maybe something will end up on the App Store.
  • I like your enthusiasm! For me, I'd developed a couple things for the vivoactive before I had one. Maybe I shouldn't tell you this - but the first time I side loaded them, they both just crashed! :( But I got them to work fairly quickly, thanks to help from here, and getting a bit of "hands on" with the device itself.

    One thing I'll mention about an WHRM in 24/7 mode, is that it's not on all the time, but only comes on every few minutes, takes a reading, and then turns off (to save battery), so the HR data from ActMon it isn't real time - that's why the "getHeartRateHistory()" thing is involved. You can get the most recent reading, but that could still be minutes old. That's one of the things the FW folks seem to be tuning on the 235, is how often the sample is taken. Some users want it more often for better data, and others want it less often to save battery...

    As far as the power off/power on thing, I'm not sure why you'd need to go back further in history than the last time you looked at history. You can save your current "state" in the ObjectStore, and next time your watchface runs, use that "state" to start with, and that state can include data from before the history was cleared.
  • Save the current minimum and the current timestamp to the object store when you update the minimum. If the device restarts, you read the minimum and timestamp, and if the timestamp is for yesterday, set your minimum to null. It doesn't seem that complicated.

    Travis
  • Former Member
    Former Member over 9 years ago
    Save the current minimum and the current timestamp to the object store when you update the minimum. If the device restarts, you read the minimum and timestamp, and if the timestamp is for yesterday, set your minimum to null. It doesn't seem that complicated.

    Travis


    The logic is not the hard partest for me .. that I can do, but not knowing much about Garmin devices and how they work .. my code is not going to likely be the most efficient. I am not a Monkey C developer .. I know a bit of C and develop databases in my spare time and have for some time. So this is all a bit foreign to me.

    I am going to go thru the samples or any other code I can find to get me started.

    But if someone could let me know the best way to get a HR value .. that would be good ? I think I am looking at HeartRateSample or HeartRateIterator
    I am thinking HeartRateSample is the one for me.
  • Former Member
    Former Member over 9 years ago
    I think I have figured out how to get and set data to the object store .. so that is half the battle on this one.

    I just have to get the code to retrieve the HR value ?

    So .. can I force the device to read the HR value ? Or does it just retrieve the last read value ?
    (I personally would like to force the device to give me a HR value at a set interval .. ie 10 min)

    I think I can likely go forward after I know that.

    This is what I have so far. Of course it doesn't work .. but that is for tomorrow to sort out. It may be easier if I had the device .. but not for a few weeks. But I need it to build first. :o:o

    var activityHRInfo = Act.getInfo();
    var LastHRValue = activityHRInfo.getHeartRateHistory(1,"true");

    var activityHRInfo = Act.getInfo();
    var LastHRValue = activityHRInfo.HeartRateSample.heartRate;



    Kevin
  • Ok, I put together this simple watchface and it runs in the simulator (but the values don't change there), and shows how to access things. it should work on a real va-hr. It displays the max, min, hr, and timestamp for that hr, where I ask for a history of 1, and the newest first,

    using Toybox.WatchUi as Ui;
    using Toybox.Graphics as Gfx;
    using Toybox.System as Sys;
    using Toybox.Lang as Lang;
    using Toybox.ActivityMonitor as ActMon;
    using Toybox.Time.Gregorian as Calendar;

    class HRWatView extends Ui.WatchFace {

    var width=0,height=0;

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

    //! Load your resources here
    function onLayout(dc) {
    width=dc.getWidth();
    height=dc.getHeight();
    }

    //! 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) {
    // Get and show the current time
    var clockTime = Sys.getClockTime();
    var timeString = Lang.format("$1$:$2$", [clockTime.hour, clockTime.min.format("%02d")]);

    dc.setColor(Gfx.COLOR_BLACK,Gfx.COLOR_BLACK);
    dc.clear();
    dc.setColor(Gfx.COLOR_WHITE,Gfx.COLOR_TRANSPARENT);
    dc.drawText(width/2,0,Gfx.FONT_MEDIUM,timeString,Gfx.TEXT_JUSTIFY_CENTER);
    var HRH=ActMon.getHeartRateHistory(1, true);
    var HRS=HRH.next();

    dc.drawText(width/2,25,Gfx.FONT_MEDIUM,"max="+HRH.getMax(),Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText(width/2,50,Gfx.FONT_MEDIUM,"min="+HRH.getMin(),Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText(width/2,75,Gfx.FONT_MEDIUM,"hr="+HRS.heartRate,Gfx.TEXT_JUSTIFY_CENTER);

    var ts=Calendar.info(HRS.when, Time.FORMAT_SHORT);
    var tss=ts.hour.format("%d")+":"+ts.min.format("%02d");

    dc.drawText(width/2,100,Gfx.FONT_MEDIUM,"at: "+tss,Gfx.TEXT_JUSTIFY_CENTER);
    }

    //! 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() {
    }

    }



    Note: I didn't include any error checking for things like having a null values, that you'd want to include in an real app.
  • Former Member
    Former Member over 9 years ago
    Thank you ... it is appreciated. jim_m_58 I cannot say in words how much I would like to thank you for your assistance.

    EDIT ... I am done my coding. Everything is working just fine that I can tell. Just need the Vivoactive HR now.

    I have to wait for a while until I can get a Vivoactive HR, they are really slow to get them here in Canada. Like several weeks to a month behind the US from what I have seen. I am going to the mall today .. and will be talking to the girl at a big retailer to see when they will get them. I do not want to order online due to return / warranty issues.