Timestamp subtraction from msg objects

Hello,
I have the following problem:
I have another flow created which returns JSON like this:

{"payload":195,"topic":"/lights/Aaron/cmd","timestamp":1676613795211}

With timestamp being the time in milliseconds since 1970 and payload and topic being irrelevant for this task.
These msg objects come in dynamic intervals and at very different times.

I now want to subtract the last timestamp value from the current one and output it (for demo purpose using a debug node, later into a file)

How can I do this?

Best Regards
Aaron

Maybe this example will help you. It could be simpler but i thought i would show how to store previous timestamps and relate them to the topic.

[{"id":"1cde623e449fc25f","type":"inject","z":"65617ffeb779f51c","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"},{"p":"timestamp","v":"","vt":"date"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"lights/Aaron/cmd","payload":"195","payloadType":"num","x":160,"y":60,"wires":[["bd7250df945b177b"]]},{"id":"bd7250df945b177b","type":"change","z":"65617ffeb779f51c","name":"","rules":[{"t":"set","p":"previous_timestamp","pt":"msg","to":"previous_timestamps[msg.topic]","tot":"flow"},{"t":"set","p":"time_diff","pt":"msg","to":"$$.timestamp - $$.previous_timestamp","tot":"jsonata"},{"t":"set","p":"previous_timestamps[msg.topic]","pt":"flow","to":"timestamp","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":380,"y":60,"wires":[["a2c6b2a0fe0b68a2"]]},{"id":"a2c6b2a0fe0b68a2","type":"debug","z":"65617ffeb779f51c","name":"debug 238","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"time_diff","statusType":"msg","x":570,"y":120,"wires":[]}]

Hope it helps

1 Like

@E1cid: Thank you very much :grinning::grinning: for your help.
I've integrated this to the place where I needed it and (after some editing because I actually needed a bit less of functionality - I didn't want the "one value per topic" thing so just edited that out) it just works!

My usecase

I use it as part of my custom solution for some kind of "light show recording system" which I built myself. This works in a way that when I play a song on my phone, the phone sends a MQTT message with information about the song (the title, album, artist and more) to NR. If there is a lightshow configured for that song, the corresponding flow gets started. Such a flow looks like a sequence of delay-,change-,delay-,change-node and so forth, which contains the commands that my lights should get, and also the delays between them.
For creating these flows, I have an M5STACK Core2 device (which is essentially an ESP32 with a battery a touchscreen, 3 (touch-)buttons and even more) where I have some buttons on the touchscreen that trigger events in NR.
When I create a lightshow, I press these buttons in a way that my lights do what I want (brightness, color change, or even a strobe or a "round-blinking effect"). Then, these events are recorded by this flow:

[
    {
        "id": "5295a3249041ba5a",
        "type": "tab",
        "label": "MQTT Recorder",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "d2b9a29ebdf2f3bc",
        "type": "mqtt in",
        "z": "5295a3249041ba5a",
        "name": "",
        "topic": "/m5Core2/states/touch",
        "qos": "0",
        "datatype": "auto-detect",
        "broker": "bc93d299d4d38301",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "x": 120,
        "y": 40,
        "wires": [
            [
                "75ba668ace844414"
            ]
        ]
    },
    {
        "id": "7f5d414d485637d9",
        "type": "function",
        "z": "5295a3249041ba5a",
        "name": "function 60",
        "func": "msg.payload = {\"payload\":msg.payload,\"topic\":msg.topic,\"timestamp\":new Date().getTime(),\"lastDelay\":msg.tsdiff};\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 610,
        "y": 40,
        "wires": [
            [
                "4a4c18a859fbc7db"
            ]
        ]
    },
    {
        "id": "75ba668ace844414",
        "type": "switch",
        "z": "5295a3249041ba5a",
        "name": "",
        "property": "recordBPs",
        "propertyType": "global",
        "rules": [
            {
                "t": "true"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 290,
        "y": 40,
        "wires": [
            [
                "adfb6fc471e8d51d"
            ]
        ]
    },
    {
        "id": "4a4c18a859fbc7db",
        "type": "file",
        "z": "5295a3249041ba5a",
        "name": "",
        "filename": "/home/pi/.sys/recordLog",
        "filenameType": "str",
        "appendNewline": true,
        "createDir": false,
        "overwriteFile": "false",
        "encoding": "none",
        "x": 810,
        "y": 40,
        "wires": [
            []
        ]
    },
    {
        "id": "3646f14a448dd7b7",
        "type": "inject",
        "z": "5295a3249041ba5a",
        "name": "",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "1",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "recordBPs",
        "payloadType": "global",
        "x": 130,
        "y": 250,
        "wires": [
            [
                "6b48905ab72ece93"
            ]
        ]
    },
    {
        "id": "6b48905ab72ece93",
        "type": "switch",
        "z": "5295a3249041ba5a",
        "name": "",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "neq",
                "v": "",
                "vt": "prev"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 290,
        "y": 250,
        "wires": [
            [
                "76ba2c4dfc946496",
                "4f765a38e81ce414"
            ]
        ]
    },
    {
        "id": "76ba2c4dfc946496",
        "type": "switch",
        "z": "5295a3249041ba5a",
        "name": "",
        "property": "recordBPs",
        "propertyType": "global",
        "rules": [
            {
                "t": "true"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 410,
        "y": 250,
        "wires": [
            [
                "5e04c572227e0b21"
            ]
        ]
    },
    {
        "id": "20c0b68cae269ae5",
        "type": "file",
        "z": "5295a3249041ba5a",
        "name": "",
        "filename": "/home/pi/.sys/recordLog",
        "filenameType": "str",
        "appendNewline": false,
        "createDir": false,
        "overwriteFile": "delete",
        "encoding": "none",
        "x": 810,
        "y": 250,
        "wires": [
            [
                "eccc5c89920d4490"
            ]
        ]
    },
    {
        "id": "5e04c572227e0b21",
        "type": "change",
        "z": "5295a3249041ba5a",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "",
                "tot": "str"
            },
            {
                "t": "delete",
                "p": "#:(file)::previous_timestamps",
                "pt": "flow"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 570,
        "y": 250,
        "wires": [
            [
                "20c0b68cae269ae5"
            ]
        ]
    },
    {
        "id": "4f765a38e81ce414",
        "type": "ui_switch",
        "z": "5295a3249041ba5a",
        "name": "",
        "label": "MQTT Steuerungsbefehle aufzeichen",
        "tooltip": "",
        "group": "17d51addf9f44c6c",
        "order": 4,
        "width": 0,
        "height": 0,
        "passthru": true,
        "decouple": "false",
        "topic": "topic",
        "topicType": "msg",
        "style": "",
        "onvalue": "true",
        "onvalueType": "bool",
        "onicon": "",
        "oncolor": "",
        "offvalue": "false",
        "offvalueType": "bool",
        "officon": "",
        "offcolor": "",
        "animate": false,
        "className": "",
        "x": 190,
        "y": 310,
        "wires": [
            [
                "d3b7991120e64152"
            ]
        ]
    },
    {
        "id": "d3b7991120e64152",
        "type": "change",
        "z": "5295a3249041ba5a",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "recordBPs",
                "pt": "global",
                "to": "payload",
                "tot": "msg",
                "dc": true
            },
            {
                "t": "set",
                "p": "isLSrunning",
                "pt": "global",
                "to": "payload",
                "tot": "msg",
                "dc": true
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 450,
        "y": 310,
        "wires": [
            []
        ]
    },
    {
        "id": "fa1be33f27cb769a",
        "type": "mqtt in",
        "z": "5295a3249041ba5a",
        "name": "",
        "topic": "/lights/Aaron/cmd",
        "qos": "0",
        "datatype": "auto-detect",
        "broker": "bc93d299d4d38301",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "x": 100,
        "y": 80,
        "wires": [
            [
                "75ba668ace844414"
            ]
        ]
    },
    {
        "id": "e7646f323d55d8a4",
        "type": "mqtt in",
        "z": "5295a3249041ba5a",
        "name": "",
        "topic": "/sys/auto/cmd",
        "qos": "0",
        "datatype": "auto-detect",
        "broker": "bc93d299d4d38301",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "x": 90,
        "y": 120,
        "wires": [
            [
                "75ba668ace844414"
            ]
        ]
    },
    {
        "id": "eccc5c89920d4490",
        "type": "function",
        "z": "5295a3249041ba5a",
        "name": "function 68",
        "func": "msg.payload = {\"event\":\"START\",\"timestamp\":new Date().getTime(),\"auto\":global.get(\"auto\",\"file\"),\"motion\":global.get(\"motion\",\"file\")}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1035,
        "y": 250,
        "wires": [
            [
                "4a4c18a859fbc7db"
            ]
        ]
    },
    {
        "id": "a25fedc1256f763e",
        "type": "mqtt in",
        "z": "5295a3249041ba5a",
        "name": "",
        "topic": "/sys/music/phone/title",
        "qos": "0",
        "datatype": "auto-detect",
        "broker": "bc93d299d4d38301",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "x": 120,
        "y": 165,
        "wires": [
            [
                "75ba668ace844414"
            ]
        ]
    },
    {
        "id": "adfb6fc471e8d51d",
        "type": "change",
        "z": "5295a3249041ba5a",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "timestamp",
                "pt": "msg",
                "to": "",
                "tot": "date"
            },
            {
                "t": "set",
                "p": "previous_timestamp",
                "pt": "msg",
                "to": "#:(file)::previous_timestamps[0]",
                "tot": "flow"
            },
            {
                "t": "set",
                "p": "tsdiff",
                "pt": "msg",
                "to": "$$.timestamp- $$.previous_timestamp",
                "tot": "jsonata"
            },
            {
                "t": "set",
                "p": "#:(file)::previous_timestamps[0]",
                "pt": "flow",
                "to": "timestamp",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 440,
        "y": 40,
        "wires": [
            [
                "7f5d414d485637d9"
            ]
        ]
    },
    {
        "id": "bc93d299d4d38301",
        "type": "mqtt-broker",
        "name": "",
        "broker": "localhost",
        "port": "1883",
        "clientid": "NodeRed",
        "autoConnect": true,
        "usetls": false,
        "protocolVersion": "4",
        "keepalive": "59",
        "cleansession": true,
        "birthTopic": "/status/rpi4",
        "birthQos": "0",
        "birthRetain": "false",
        "birthPayload": "CONNECTED",
        "birthMsg": {},
        "closeTopic": "/status/rpi4",
        "closeQos": "0",
        "closeRetain": "false",
        "closePayload": "DISCONNECTED",
        "closeMsg": {},
        "willTopic": "/status/rpi4",
        "willQos": "0",
        "willRetain": "false",
        "willPayload": "C_ERROR",
        "willMsg": {},
        "userProps": "",
        "sessionExpiry": ""
    },
    {
        "id": "17d51addf9f44c6c",
        "type": "ui_group",
        "name": "Default",
        "tab": "e186d7d116ed422a",
        "order": 1,
        "disp": false,
        "width": "6",
        "collapse": false,
        "className": ""
    },
    {
        "id": "e186d7d116ed422a",
        "type": "ui_tab",
        "name": "LightRecorder",
        "icon": "dashboard",
        "order": 7,
        "disabled": false,
        "hidden": false
    }
]
```, which prints them to a file where the MQTT topic, the value, and the timestamp with the amount of time since the last command. I then proccess the delays and the other data to a flow that looks like I described above, link them to the song (update a big switch node which starts the flow for every song), and then these commands get run every time I play that song. I integrated your flow into the "recorder" part of the system so I won't have to subtract the timestamps after recording it.

Thanks for your help
Aaron

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.