AntPlusListener events not firing

In my Watch App i am trying to get an event to fire every time an AntPlus device data is updated.  Specifically every time power is updated from a power meter.

To do this I am trying to use BikePowerListener.

if I copy the code from the example in the documentation: 

https://developer.garmin.com/connect-iq/api-docs/Toybox/AntPlus/BikePowerListener.html

And remove the ListItem references as I can't see how to use them, everything initializes fine, but the OnCalculatedPowerUpdate event never fires.  Elsewhere in code I am acessing the data using the "getBikePowerData" function below, so the device is connected and working.  Why isn't the callback firing?

Here is my class:

using Toybox.AntPlus;
using Toybox.System as Sys;

class antplus_bpwr extends AntPlus.BikePowerListener
{
	hidden var _antplus_bpwr;
	hidden var _antplus_listener;
	hidden var _sample_count;
	hidden var _samples;
	hidden var _head;
	hidden var _max_samples_count = 12;	// 3 seconds at 4Hz..
	
	function initialize()
	{
		// Initialise BSC device:
		BikePowerListener.initialize();
    	Sys.println("BWPR Initialized.");
		_antplus_bpwr = new AntPlus.BikePower(null);
		_sample_count = 0;
		_head = 0;
		_samples = new [_max_samples_count];
	}
	
	// Class to store data.  Currently just power but could be other stuff too.  
	// Keep like this for consistency.
	class bpwr_data
	{
		var power;
		function initialize()
		{
			power = 0;
		}
	}
	
	// Function to return bike power data object.
	function getBikePowerData()
	{
		var ret = new bpwr_data();
    	var info = _antplus_bpwr.getCalculatedPower();
    	if (info!=null)
    	{
    		if (info.power > 0)
    		{
    			ret.power = info.power;
    		}
    	}
    	return ret;
	}
	
	// Returns device number.
	function getDeviceNumber()
	{
		return _antplus_bpwr.getDeviceState().deviceNumber;
	}
	
	// Callback on power update.
	function onCalculatedPowerUpdate(data)
	{
		Sys.println("Updating power");
		_samples[_head] = data.power;
		if ((_sample_count + 1) < _max_samples_count)
		{
			_sample_count++;
		}
		_head++;
		if (_head == _max_samples_count)
		{
			_head = 0;
		}
	}
	
	// get average power.
	function getAvgPower()
	{
		var ret = 0;
		if (_sample_count == 0) {return ret;}
		for (var i=0;i<_sample_count;i++)
		{
			ret+=_samples[i];
		}
		ret/=_sample_count;
		return ret;
	}
	
}

Top Replies

  • Thank you Kurev.  The bike power object is working though - I can read data from the sensor, it is just the callback that isn't firing.

    That's exactly it. To use BikePower APIs like…

All Replies

  • As I mentioned in another thread, make sure you are calling

    Sensor.setEnabledSensors();  //provide an array of sensors your app uses

    In a device/watch app, this is how the watch connects to a native sensor.

  • I believe problem is here:

    _antplus_bpwr = new AntPlus.BikePower(null);

    Instead of null, you should give instance of your BikePowerListener as listener parameter. However in this case, not sure how it should be. Perhaps 'self' ? I instanciate elsewhere in the code first my implementation of BikePowerListener, and then instanciate BikePower, using my listener instance as parameter.

    Refer to:

    developer.garmin.com/.../BikePower.html

  • Thank you Kurev.  The bike power object is working though - I can read data from the sensor, it is just the callback that isn't firing.

    Jim, why then am I able to read data from the bike power sensor, even though I have not enabled it through the sensor class?  

    I have to say the documentation is very poor, and lack of AntPlus examples make development very painful!  Thank you for your help though. Without that I would be really stuck.

  • Jim, I have tried this and makes no difference.

    Would someone at Garmin be able to test my code and tell me why its not working?  Here is code with Sensor enabled as Jim suggests.

    using Toybox.AntPlus;
    using Toybox.System as Sys;
    using Toybox.Sensor;
    
    class antplus_bpwr extends AntPlus.BikePowerListener
    {
    	hidden var _antplus_bpwr;
    	hidden var _antplus_listener;
    	hidden var _sample_count;
    	hidden var _samples;
    	hidden var _head;
    	hidden var _max_samples_count = 12;	
    	
    	function initialize()
    	{
    		// Initialise BSC device:
    		BikePowerListener.initialize();
        	Sys.println("BWPR Initialized.");
        	Sensor.setEnabledSensors([Sensor.SENSOR_BIKEPOWER]);
    		_antplus_bpwr = new AntPlus.BikePower(null);
    		_sample_count = 0;
    		_head = 0;
    		_samples = new [_max_samples_count];
    	}
    	
    	// Class to store data.  Currently just power but could be other stuff too.  
    	// Keep like this for consistency.
    	class bpwr_data
    	{
    		var power;
    		function initialize()
    		{
    			power = 0;
    		}
    	}
    	
    	// Function to return bike power data object.
    	function getBikePowerData()
    	{
    		var ret = new bpwr_data();
        	var info = _antplus_bpwr.getCalculatedPower();
        	if (info!=null)
        	{
        		if (info.power != null)
        		{
    	    		if (info.power > 0)
    	    		{
    	    			ret.power = info.power;
    	    		}
    	    	}
        	}
        	return ret;
    	}
    	
    	// Returns device number.
    	function getDeviceNumber()
    	{
    		return _antplus_bpwr.getDeviceState().deviceNumber;
    	}
    	
    	// Callback on power update.
    	function onCalculatedPowerUpdate(data)
    	{
    		Sys.println("Updating power");
    		_samples[_head] = data.power;
    		if ((_sample_count + 1) < _max_samples_count)
    		{
    			_sample_count++;
    		}
    		_head++;
    		if (_head == _max_samples_count)
    		{
    			_head = 0;
    		}
    	}
    	
    	// get average power.
    	function getAvgPower()
    	{
    		var ret = 0;
    		if (_sample_count == 0) {return ret;}
    		for (var i=0;i<_sample_count;i++)
    		{
    			ret+=_samples[i];
    		}
    		ret/=_sample_count;
    		return ret;
    	}
    	
    }

    I am expecting "Updating power" to print in the "onCalculatedPowerUpdate" function.

    The callback should fire any time after initialising the class.

  • Are you only trying this in the sim, or on a real device?  If only the sim, try a real device.

    Oh, and make sure the sensor is paired to the device and awake.

  • Thank you Kurev.  The bike power object is working though - I can read data from the sensor, it is just the callback that isn't firing.

    That's exactly it. To use BikePower APIs like getBikePowerData(), you don't even need listener object if you only do polling. That's why it is working even if you give null as listener

    If you want the callbacks coming to your listener though, you need to connect the BikePower and listener, and this is done as I described and is shown in BikePower API document.

    // Assuming Valid BikePowerListener object "MyBikePowerListener"
    
    // Initialize the AntPlus.BikePowerListener object
    listener = new MyBikePowerListener();
    
    // Initialize the AntPlus.BikePower object with a listener
    bikePower = new AntPlus.BikePower(listener);

  • I have tried on both sim and real device, and neither work.  Sensor is of course paired and awake - as I say I am able to see the bike power data, but the event does not fire.

    Thank you.

  • Try what Kurev is suggesting.  But you may not even need a listener.

    Let's save you want both HR and Power, you can set a callback for Sensor data with Sensor.enableSensorEvents().  That way, you get a single callback for both sensors, about once a second.

  • Thats the ticket.  Thank you!

  • Actually this is working in sim but not on real device.  Any ideas why that may be?  here is my class:

    using Toybox.AntPlus;
    using Toybox.System as Sys;
    
    class antplus_bpwr_listener extends AntPlus.BikePowerListener
    {
    	hidden var _antplus_bpwr;
    	hidden var _antplus_listener;
    	hidden var _sample_count;
    	hidden var _samples;
    	hidden var _head;
    	hidden var _max_samples_count = 3;	
    	
    	function initialize()
    	{
    		_sample_count = 0;
    		_head = 0;
    		_samples = new [_max_samples_count];
    		BikePowerListener.initialize();
    	}
    	
    	// Callback on power update.
    	function onCalculatedPowerUpdate(data)
    	{
    		var pwr = data.power;
    		Sys.println("Updating power = " + pwr);
    		if (pwr >= 0)
    		{
    			_samples[_head] = pwr;
    			if (_sample_count < _max_samples_count)
    			{
    				_sample_count++;
    			}
    			_head++;
    			if (_head == _max_samples_count)
    			{
    				_head = 0;
    			}
    		}
    	}
    	
    	// get average power.
    	function getAvgPower()
    	{
    		var ret = 0.0f;
    		if (_sample_count == 0) {return ret;}
    		for (var i=0;i<_sample_count;i++)
    		{
    			ret+=_samples[i];
    		}
    		ret/=_sample_count;
    		return ret;
    	}
    }
    
    class antplus_bpwr
    {
    	hidden var m_bpwr;
    	hidden var m_listener;
    	function initialize()
    	{
    		m_listener = new antplus_bpwr_listener();
    		m_bpwr = new AntPlus.BikePower(m_listener);
    	}
    	
    	// Class to store data.  Currently just power but could be other stuff too.  
    	// Keep like this for consistency.
    	class bpwr_data
    	{
    		var power;
    		function initialize()
    		{
    			power = -1;
    		}
    	}
    	
    	// Returns device number.
    	function getDeviceNumber()
    	{
    		return _antplus_bpwr.getDeviceState().deviceNumber;
    	}
    	
    	// Function to return bike power data object.
    	function getData()
    	{
    		var ret = new bpwr_data();
        	var info = m_bpwr.getCalculatedPower();
        	if (info!=null)
        	{
        		if (info.power != null)
        		{
    	    		if (info.power > 0)
    	    		{
    	    			ret.power = info.power;
    	    		}
    	    	}
        	}
        	return ret;
    	}
    	
    	// get average power.
    	function getAvgPower()
    	{
    		return m_listener.getAvgPower();
    	}
    	
    	
    }