MCF88 Time Sync

Hello,

We have a few MCF88 devices, normally we disable time sync when we deploy using the NFC programming and then just assume sensor readings are at the receiving server’s UTC time stamp or in the case of multiple readings offset them by the appropriate amount of minutes… However we forgot to disable time sync on one device and we can’t easily get to it now it’s out in the field.

Does anyone have an example downlink generation for MCF88 time sync answer that we can use in Node-Red or equivalent in response to the time sync requests. If need be I’ll have a crack at writing it myself but I cannot believe with the number of these sensors deployed nobody has this to hand.

Already searched the forums and Github to no avail :frowning:

Best Regards,

Rob

What does the manufacturer think?

You won’t need to write any code, just enter it on the console.

Hi, here:

https://iot.mcf88.cloud/LoRaWeb/#/configuration

after free registration, you can find manuals, javascript examples, downlink generator, uplink decoder, firmware updates and different tools under “resources”, also the time sync function. Regards

I’ve done that few years ago, and it was far for painless, but followed instructions of @francozampicinini and succeeded with node red flow connected (thru MQTT) to chirpstack server

it won’t works out of the box but you have 95% of the stuff done in this function node of node red

function getHexDate(data) 
{
    var year = data.getUTCFullYear() - 2000;
    var month = data.getUTCMonth() +1 ;
    var day = data.getUTCDate();
    var hour = data.getUTCHours();
    var minute = data.getUTCMinutes();
    var second = data.getUTCSeconds() / 2;
    
    var longData = (second & 0x1F) + ((minute << 5) & 0x07E0) + ((hour << 11) & 0xF800) + ((day << 16) & 0x1F0000) + ((month << 21) & 0x1E00000) + ((year << 25) & 0xFE000000);
    var hexData = longData.toString(16);

    var hexDate = (hexData.substring(6, 8) + hexData.substring(4, 6) + hexData.substring(2, 4) + hexData.substring(0, 2)).toUpperCase();
    return hexDate;
}

function parseTimeSync(payload) 
{
    const uplinkId = payload.substring(0, 2);
    if (uplinkId.toUpperCase() === '01') {
        const syncID = {
            variable: 'syncID',
            value: payload.substring(2, 10)
        };
        const syncVersion = {
            variable: 'syncVersion',
            value: payload.substring(10, 12) + "." + payload.substring(12, 14) + "." + payload.substring(14, 16)
        };
        const applicationType = {
            variable: 'applicationType',
            value: payload.substring(16, 20)
        };
        const rfu = {
            variable: 'rfu',
            value: payload.substring(20)
        };

        return [
            syncID,
            syncVersion,
            applicationType,
            rfu
        ];
    } else {
        return null;
    }
}

function getDownlinkTimeSync(payload, date) 
{
    const uplinkId = payload.substring(0, 2);
    if (uplinkId.toUpperCase() === '01') {
        var syncID = null;

        var content = parseTimeSync(payload);

        if (content !== null) {
            if (content[3].value !== '02') { //value for Option byte. 01 if first message after boot - 02 if external power is going down
                for (var i = 0; i < content.length; i++) {
                    if (content[i].variable === 'syncID') {
                        syncID = content[i].value;
                    }
                }

                if (syncID !== null) {
                    return '00' + syncID + getHexDate(date);
                } 
            } 
        } 
    }
}

// Downlink payload to send (MQTT -> Chirpstack)
var newMsg = {}
newMsg.payload = {
    "confirmed": false,
    "fPort": 2,
}

// Get time of received payload frame 
var date = new Date(msg.payload.time); 

newMsg.downlink = getDownlinkTimeSync(msg.payload.data, date );

// convert hex downlink to base64 for chirpstack
newMsg.payload.data = Buffer.from(newMsg.downlink , 'hex').toString('base64');
// send to device 
newMsg.topic = "application/1/device/" + msg.payload.devEUI + "/command/down"

return newMsg;

hope this help