In case anyone's interested:
I took the concept of flow-timer and created my own timer/stopwatch subflow:
[
{
"id": "a83b77052e22c05e",
"type": "subflow",
"name": "StopWatch",
"info": "",
"category": "",
"in": [
{
"x": 60,
"y": 40,
"wires": [
{
"id": "ba4169e0fb4f892f"
}
]
}
],
"out": [
{
"x": 710,
"y": 40,
"wires": [
{
"id": "ba4169e0fb4f892f",
"port": 0
}
]
}
],
"env": [],
"meta": {},
"color": "#87A980",
"inputLabels": [
"command input"
],
"outputLabels": [
"return"
],
"icon": "font-awesome/fa-clock-o"
},
{
"id": "ba4169e0fb4f892f",
"type": "function",
"z": "a83b77052e22c05e",
"name": "stopwatch",
"func": "var chrono = global.get(\"stopwatch\") || {};\n\nif (msg.stopwatch !== undefined) {\n if (chrono[msg.stopwatch.name] === undefined){\n chrono[msg.stopwatch.name] = { job:\"\", elapsed:0, startPoint:null, stopPoint: null, lastCommand: \"\" };\n }\n \n if (msg.stopwatch.command == \"start\"){\n if ((chrono[msg.stopwatch.name].lastCommand != \"start\") ||\n ((chrono[msg.stopwatch.name].lastCommand == \"start\") && (chrono[msg.stopwatch.name].order != msg.stopwatch.order))){\n if ((chrono[msg.stopwatch.name].lastCommand == \"end\") || (chrono[msg.stopwatch.name].order != msg.stopwatch.order)){\n chrono[msg.stopwatch.name].job = msg.stopwatch.job;\n chrono[msg.stopwatch.name].elapsed = 0;\n }\n msg.stopwatch.startPoint = Date.now();\n chrono[msg.stopwatch.name].startPoint = msg.stopwatch.startPoint;\n }\n } else if ((msg.stopwatch.command == \"stop\") || (msg.stopwatch.command == \"end\")) {\n msg.stopwatch.stopPoint = Date.now();\n if (chrono[msg.stopwatch.name].startPoint !== null){\n chrono[msg.stopwatch.name].stopPoint = msg.stopwatch.stopPoint;\n chrono[msg.stopwatch.name].elapsed += chrono[msg.stopwatch.name].stopPoint - chrono[msg.stopwatch.name].startPoint;\n chrono[msg.stopwatch.name].stopPoint = null;\n chrono[msg.stopwatch.name].startPoint = null;\n }\n }\n msg.stopwatch.elapsed = chrono[msg.stopwatch.name].elapsed;\n chrono[msg.stopwatch.name].lastCommand = msg.stopwatch.command;\n global.set(\"stopwatch\", chrono);\n}\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 340,
"y": 40,
"wires": [
[]
]
},
{
"id": "c6555eda535400fe",
"type": "subflow:a83b77052e22c05e",
"z": "b8bde5487c0b24fa",
"name": "",
"x": 430,
"y": 120,
"wires": [
[
"4665f495b811c70a"
]
]
}
]
The basic idea is that you add a stopwatch property in the message. Here you can send:
- command : "start", "stop", or "end".
- name : the name of the process/machine you're monitoring
- job: the name of the recipe/job that you are monitoring within the machine or process.
The subflow will check first if the machine has a timer on the global variables or not. If not, it will create it.
If the command sent is "start" and the last command was blank or was "end", it will record the timestamp (in ms) for the starting point, as well as the job name. If the last command sent to this machine was also "start" but for a different job, the start point will be overwritten. In both cases, the elapsed time will be set to 0. If the last command was "stop", it will keep the elapsed time as intact.
If the command sent was "stop", and the last one was "start", it will calculate the difference between the stop and start timestamps, and add it to the "elapsed" property in the timer. It won't do anything for any other case.
If the command sent is "end", it will calculate the difference and add it to elapsed, but it will set both start and stop timestamps to null.
In all cases, the node will store the timer values in the global context, plus will send the elapsed time, timestamps, and last command to msg.stopwatch (for further processing down the line).
The basic idea is that you have a timer that you can start and stop as many times as you want, and it will continue adding the incremental time until you end the measurement. This is useful for controlling uptime/downtime in industrial machines or processes, where you can start a machine, then have an error, and when that error is cleared it will continue production. You can set different machine codes for uptime/downtime and control them independently, and control different recipes/procedures on the same machine by using the "job" property.