ANT LEV Read Payload

Hi,

I'am trying to get the data from my light electric vehicles (LEV) via ANT.

I started with the Moxy sample and can now connect to the bike.

But How do I have to interpret the data out of the payload ?

var payload = msg.getPayload();
This seems to be any array of 8 bytes.
Where can I find battery level and other values of the bike?

Any help really appreciated
  • Yes, that is great.

    Thanks a lot 

  • from where have you received all this information. Is there an ANT document explaining this?
    I am also search from the Power produced by the motor [W] an the human power produced by the biker [W]
    This is shown in the Fazua Mobile APP, but not listed in your code.

  • It’s not my code, I found it using google. I think the person who owns the repo is here tho

  • Hi  
    I‘m trying to write a datafield for Ant+ LEV for my Specialized Levo 2019. All I want is to connect to bike and read ID, battery status and support level. Unfortunately I did not manage so far to come along.
    I downloaded Ant+_LEV from ThisisAnt and I will attach it here. Maybe it is of any help for you.

    In revers I would be very grateful if you could share your code which would certainly help me to get along…

    Thanks!

    ANT+_LEV.pdf

  • Hi MC,

    First step:
    I took the Moxy Sample of Garmin and changed the deviceType to 20
    So I could connect my Fenix to my Fazua Bike.
    MOSensor.mc

      //const DEVICE_TYPE = 31; //Muscle Oxygen
        //const DEVICE_TYPE = 11; //Bike Power
        const DEVICE_TYPE = 20; //Light Electric Vehicle
      

    Second step:

    I read the payload according to 
    https://github.com/maca88/E-Bike-Edge-MultiField/blob/master/Source/EBikeEdgeMultiField/source/EBikeSensor.mc

    for the moment, (I am really at the beginning) I did for Battery Charge only:

    function parsePage3(payload, data) {
                data.batteryCharge = parseBatteryCharge (payload);
            }
    
    
    hidden function parseBatteryCharge(payload) {
            return (payload[1] & 0x7F); // Battery SOC (State of Charge)
    }
    
    function onMessage(msg) {
            // Parse the payload
            var payload = msg.getPayload();
    
            if( Ant.MSG_ID_BROADCAST_DATA == msg.messageId ) {
                var pageNumber = (payload[0] & 0xFF);
                if (pageNumber == 1) 
                {
                //if( MuscleOxygenDataPage.PAGE_NUMBER == (payload[0].toNumber() & 0xFF) ) {
                    // Were we searching?
                    if (searching) {
                        searching = false;
                        // Update our device configuration primarily to see the device number of the sensor we paired to
                        deviceCfg = GenericChannel.getDeviceConfig();
                    }
                    var dp = new MuscleOxygenDataPage();
                    
                    //data.batteryTemperature = parseBatteryTemperature(payload);
                    dp.parse(payload, data);
                    // Check if the data has changed
                    if (pastEventCount != data.eventCount) {
                        pastEventCount = data.eventCount;
                    }
                } else if (pageNumber == 3) {
                    var dp = new MuscleOxygenDataPage();
                    dp.parsePage3(payload, data);
                    //data.batteryCharge = parseBatteryCharge (payload);
                }
            } else if(Ant.MSG_ID_CHANNEL_RESPONSE_EVENT == msg.messageId) {
                if (Ant.MSG_ID_RF_EVENT == (payload[0] & 0xFF)) {
                    if (Ant.MSG_CODE_EVENT_CHANNEL_CLOSED == (payload[1] & 0xFF)) {
                        // Channel closed, re-open
                        open();
                    } else if( Ant.MSG_CODE_EVENT_RX_FAIL_GO_TO_SEARCH  == (payload[1] & 0xFF) ) {
                        searching = true;
                    }
                } else {
                    //It is a channel response.
                }
            }
        }
    

    It is only proof of concept, it works with FAZUA Ride 60 and Fenix 6X but should also work with your bike!
    Hope this helps you

    I am interested in BikePower and MotorPower, but this is not in LEV but shown on the Fazua App.
    There is only Assist in %, but this is only half of what I need.
    I will try to ask FAZUA where they transmit this information.

  • Many Thanks Seli17!
    I‘m also working on Moxy sample base, but I‘m afraid, I had deleted too much of code I was thinking I do not need Joy.
    So - back to the start!

    Regarding rider power: my Spesh Levo sends rider(bike) power as „normal“ sensor. I get bikepower and cadence simply by searching and connecting my Levo as power sensor. No Ant programming necessary - only activity.info.currentPower and currentCadence

    I will report back!

  • Hi 

    I managed to get batterySOC, assistMode, totalAssistModes to work.

    I followed your steps, but simply parse the variables inside of onMessage() and then I pass it via function call from/to MoxyField.mc
    I tested the output on my Edge 1040 and with my Spesh Levo - it works!

        public function onMessage(msg as Message) as Void {
            // Parse the payload
            var payload = msg.getPayload();
            //if ((Ant.MSG_ID_BROADCAST_DATA == msg.messageId) && ($.PAGE_NUMBER == (payload[0].toNumber() & 0xFF))) {
            if ( Ant.MSG_ID_BROADCAST_DATA == msg.messageId) {
                var pageNumber = (payload[0] & 0xFF);
                if (pageNumber == 1) {
                    // Were we searching?
                    if (_searching) {
                        _searching = false;
                        // Update our device configuration primarily to see the device number of the sensor we paired to
                        _deviceCfg = GenericChannel.getDeviceConfig();
                    }
                    _data.parse(msg.getPayload());
                    // Update the event count
                    _pastEventCount = _data.getEventCount();
                } else if (pageNumber == 3) {
                    batSOC = (payload[1] & 0x7F);       //battery Status
                    travelMode = (payload[2] >> 3 & 0x07);      //Assist Mode
                } else if (pageNumber == 5) {
                    totalAssistModes = (payload[2] >> 3) & 0x07; // Number of Assist modes supported
                } else if (pageNumber == 80) {
                    manufacturerId = (payload[5] << 8) | payload[4]; // Manufacturer ID
                }             
    
            } else if ((Ant.MSG_ID_CHANNEL_RESPONSE_EVENT == msg.messageId) && (Ant.MSG_ID_RF_EVENT == (payload[0] & 0xFF))) {
                if (Ant.MSG_CODE_EVENT_CHANNEL_CLOSED == (payload[1] & 0xFF)) {
                    // Channel closed, re-open
                    open();
                } else if (Ant.MSG_CODE_EVENT_RX_FAIL_GO_TO_SEARCH == (payload[1] & 0xFF)) {
                    _searching = true;
                }
            }
        }
    

    Next step:
    reduce and rename the Moxy datafield to my needs for my LEV datafield.

    A question: Does the datafield work in the simulator if a ANT dongle is connected to the PC?
    Problem for me to test: my PC is upstairs and my eBike downstairs. Too wide range for connection I assume...

    All tests I do are with the datafield sideloaded to the Edge - it's a litte complicated.

  • I added activity.info.currentPower and currentCadence to my BigFont DataField and have now to add the Moxy (LEV) stuff to it. 
    What Edge do you have?

    I have no ANT dongle, I am testing directly with my Fenix to my bike, not very confortable!
    => so same as you

  • Currently I‘m using an Edge 1040.

    I ordered a 10 m USB extension cable to bring the dongle near to my bike. Should it really work - there is another problem: my bike turns off after 5 minutes of inactivity Joy