Time difference between each receipt of MQTT packets

Please, I have a specific need that I'm having a lot of difficulty implementing.

I receive telemetry packets from the MQTT server.

These packages are about the depth of a diver.

I get it as an integer.

That's not the problem, the issue is that I need to store the exact second and/or millisecond that I receive this packet.

Because I need to calculate the time the diver sinks in the water in meters per second.

I thought of putting this data into a depth and time array.

And then calculate the difference between one and the other.

But I'm not being successful between calculating the millisecond differences within an array.

Does anyone have a suggestion?

I confess to being a little lost.



//Atribui nas váriaveis d e t para não ficar muito grande a expressão
var d = global.get("array_d");
var t = global.get("array_t");

d.unshift(msg.payload); // Adiciona no Inicio do Array
d.pop();                //Remove o últim array para manter a posição fixa


let iData = new Date().valueOf();
let fData = new Date().valueOf();


t.unshift(iData);      // Adiciona no Inicio do Array
t.pop();                //Remove o últim array para manter a posição fixa


node.warn("iData:" + iData);
node.warn("fData:" + fData);

var diff = fData - iData;
node.warn("Diff:" + diff);


node.warn("t[0]:" + t[0]);
node.warn("t[1]:" + t[1]);

var diferenca = t[1] - t[0];

diferenca = diferenca / 1000;

node.warn(diferenca);

//node.warn(msg.myrawdate);




return msg;


Acima é a tela com o fluxo recebendo os dados do servidor MQTT.

This will be the diver's speed control screen.

image

The calculations and the code to do them are faily trivial however it is not 100% clear what you are after exactly.

For example: measuring meters per second requires 2 or more samples. The more samples, the less reactive & more "smoothed" the value becomes. With less samples, you get a more responsive value but will see lots of "flicker"

Here is some starter code demo to get you going. Give it a go an see what you can make from it.

Demo Flow (use CTRL+I to import):

[{"id":"db754a27c7f0d048","type":"inject","z":"73b44920080e0db3","name":"depth 1m","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"diver/1/depth","payload":"1","payloadType":"num","x":1640,"y":60,"wires":[["24aca97f750e741e"]]},{"id":"a957732b4f3bd45b","type":"inject","z":"73b44920080e0db3","name":"depth 2m","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"diver/1/depth","payload":"2","payloadType":"num","x":1640,"y":100,"wires":[["24aca97f750e741e"]]},{"id":"a38dec9b04236ab1","type":"inject","z":"73b44920080e0db3","name":"depth 3m","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"diver/1/depth","payload":"3","payloadType":"num","x":1640,"y":140,"wires":[["24aca97f750e741e"]]},{"id":"77f1632662d34689","type":"inject","z":"73b44920080e0db3","name":"depth 4m","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"diver/1/depth","payload":"4","payloadType":"num","x":1640,"y":180,"wires":[["24aca97f750e741e"]]},{"id":"6ecee1e4b4a7173e","type":"inject","z":"73b44920080e0db3","name":"depth 5m","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"diver/1/depth","payload":"5","payloadType":"num","x":1640,"y":220,"wires":[["24aca97f750e741e"]]},{"id":"d4628ec2adf9bb07","type":"inject","z":"73b44920080e0db3","name":"depth 6m","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"diver/1/depth","payload":"6","payloadType":"num","x":1640,"y":260,"wires":[["24aca97f750e741e"]]},{"id":"c55f3fd42cc39e0b","type":"inject","z":"73b44920080e0db3","name":"depth 7m","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"diver/1/depth","payload":"7","payloadType":"num","x":1640,"y":300,"wires":[["24aca97f750e741e"]]},{"id":"24aca97f750e741e","type":"function","z":"73b44920080e0db3","name":"calculateRateOfDescent","func":"const data = context.get('data') || []\nif (data.length > 10) {\n    data.pop()\n}\ndata.unshift({\n    depth: msg.payload,\n    timestamp: Date.now()\n})\ncontext.set('data', data)\n\nfunction calculateRateOfDescent(data) {\n    let rateOfDescent = [];\n    for (let i = 0; i < data.length - 1; i++) {\n        let depthDifference = data[i + 1].depth - data[i].depth;\n        let timeDifference = (data[i + 1].timestamp - data[i].timestamp) / 1000; // convert to seconds\n        let descentRate = depthDifference / timeDifference;\n        rateOfDescent.push(descentRate);\n    }\n    return rateOfDescent;\n}\n\nmsg.payload = calculateRateOfDescent(data)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1910,"y":160,"wires":[["9ff1e00ab7db5d29"]]},{"id":"9ff1e00ab7db5d29","type":"debug","z":"73b44920080e0db3","name":"M/sec:  +ve value == descending, -ve == ascending","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1990,"y":220,"wires":[]}]

I think there is a large assumption in your thinking that I'm not sure is correct. The time you receive the packet is NOT directly related to the movement of the diver. So if that is critical, I think you need to rethink slightly.

Really, the data from the diver needs to include a ms timestamp and you should be using that for the calculation.

The transition time from sensor send, mqtt receive, mqtt send, Node-RED receive is going to be - I'm somewhat guessing since I don't know the connection type from the diver nor the infrastructure layout) - in the region at least of 10's of ms if not a few hundred.

use a delay node.

Before the delay node store the depth in a flow variable, let's call it depth_now, after the delay node store the delayed depth again in another flow variable depth_then.

Then setup a periodic inject, route that to a function node where you read the two flow variables and then and calculate:

let rate = (depth_now - depth_then) / delay_time;

And after this I would probably also put a smooth node.

The longer you make the delay the more precise (but also slower to react) it becomes. For even more precision you need timestamped messages, then you can use the difference of the time stamps of the stored "now" and "then" messages instead of the fixed delay_time.

How many messages do you get per second and how precise do you want it to be? The answer helps to determine how long the delay, how fast the inject and how long the smooth node behind the calculation.

First of all thank you for all the help received.

You really are a community of brothers and friends.

I hope to be able to reciprocate equally one day.

2 Likes

The objective is to obtain the diver's descent velocity and the diver's ascent velocity.

Whereas there is a human health rule for that.

The telemetry equipment plugged into its body sends depth data via "optical fiber", so I disregard the delay between sending and receiving by the "MQTT Server" and the Node-Red server, perhaps a few insignificant milliseconds.

I set the sensor to send a sample every 1 second. But I can do it every 0.5 seconds or 0.25 seconds according to python programming.

The connection between the diver and the MQTT/Node-Red Server is via Fiber Optic over an Ethernet network.

I could even put a timestamp on the mqtt data, but I found that insignificant.

Because the connection is instantaneous.

The displacement speed.

It is measured in meters per minute for the descent.

And meters per minute for ascent

I modified the code to understand meters per minute.

Please help me is correct ?

[
    {
        "id": "24aca97f750e741e",
        "type": "function",
        "z": "f8343d4a67d0c916",
        "name": "calculateRateOfDescent",
        "func": "const data = context.get('data') || []     //Create array\nif (data.length > 10) {                    // if remove last element of array\n    data.pop()\n}\ndata.unshift({                             //insert new element in array\n    depth: msg.payload,\n    timestamp: Date.now()\n})\ncontext.set('data', data)                 //set var data\n\nfunction calculateRateOfDescent(data) {\n    let vDescida\n    //let rateOfDescent = [];          //- is not need deliver in array\n    for (let i = 0; i < data.length - 1; i++) {\n        let depthDifference = data[i + 1].depth - data[i].depth;\n        let timeDifference = (data[i + 1].timestamp - data[i].timestamp) / 1000; // Convert to seconds\n        //let descentRate = depthDifference / timeDifference;\n        let vDescida = depthDifference / timeDifference;\n        vDescida = vDescida * 60; //Convert to minutes \n        //rateOfDescent.push(descentRate);\n    }\n    //return rateOfDescent;\n    return vDescida;\n}\n\nmsg.payload = calculateRateOfDescent(data)\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 430,
        "y": 200,
        "wires": [
            [
                "7fd322ae44092954",
                "717730e5948c1529",
                "021205d3082bf1f9"
            ]
        ]
    }
]