OpenMarine

Full Version: Node Red Engine Hours timer
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi all
I've spent a while putting together a Node Red Engine hours flow.
Its not the prettiest thing but I thought I'd share it here for the benefit of other NR newbies like me who are also going down the same path or wanting to implement other timers.

The counter is perpetually stored on Engine OFF so a RPi shutdown wont loose the count.
That said, I've no idea if the store would survive a NodeRed upgrade so Ive included an Inject Node which can be used to Zero the counter or preload an existing Hour Count (don't forget to make a note of the count before doing an NR or OP upgrade !).

In my setup the counter is triggered by an MQTT message generated by a remote sender when the engine is started. The counter is started/stopped with "1" or "0" so easy to modify the start trigger.

Bye the way, before you say it, no I dont time my engine running time to the second but its useful to have seconds ticking when testing and can easily be removed from the display.
 
Cheers

Code:
[
   {
       "id": "3726e20.932761e",
       "type": "ui_text",
       "z": "2b47cf3c.1f345",
       "group": "2381998f.63b6d6",
       "order": 7,
       "width": 0,
       "height": 0,
       "name": "",
       "label": "Engine Hrs (Total)",
       "format": "{{msg.payload}}",
       "layout": "row-spread",
       "x": 670,
       "y": 540,
       "wires": []
   },
   {
       "id": "cbaed108.85542",
       "type": "inject",
       "z": "2b47cf3c.1f345",
       "name": "Ticker",
       "topic": "",
       "payload": "",
       "payloadType": "date",
       "repeat": "1",
       "crontab": "",
       "once": true,
       "x": 160,
       "y": 420,
       "wires": [
           [
               "c3696e78.931fe",
               "be88c4f1.d85998",
               "f4ebe418.011268"
           ]
       ]
   },
   {
       "id": "c3696e78.931fe",
       "type": "function",
       "z": "2b47cf3c.1f345",
       "name": "Send Tick if Eng ON",
       "func": "var engineon = global.get(\"engineon\");\nif (engineon === 0){\n    msg.reset = true;\n}else if (engineon === 1){\n    msg.payload = \"tick\";\n    return msg;\n}",
       "outputs": 1,
       "noerr": 0,
       "x": 380,
       "y": 420,
       "wires": [
           [
               "f18b1e29.57f6b"
           ]
       ]
   },
   {
       "id": "5b511c3d.d31514",
       "type": "change",
       "z": "2b47cf3c.1f345",
       "name": "",
       "rules": [
           {
               "t": "set",
               "p": "engineon",
               "pt": "global",
               "to": "payload",
               "tot": "msg"
           }
       ],
       "action": "",
       "property": "",
       "from": "",
       "to": "",
       "reg": false,
       "x": 410,
       "y": 260,
       "wires": [
           []
       ]
   },
   {
       "id": "e3808594.7ac418",
       "type": "key-value-write",
       "z": "2b47cf3c.1f345",
       "store": "964eb4a3.b5f7d8",
       "action": "set",
       "key": "",
       "keyvalue": "",
       "name": "Write to store",
       "x": 970,
       "y": 660,
       "wires": [
           [
               "33bd62f2.6fc79e",
               "92d95cd.b9113a"
           ]
       ]
   },
   {
       "id": "ac105340.cb99c",
       "type": "key-value-read",
       "z": "2b47cf3c.1f345",
       "store": "964eb4a3.b5f7d8",
       "key": "",
       "name": "Read Store",
       "x": 630,
       "y": 280,
       "wires": [
           [
               "8f2e3d11.a5be9",
               "ff81fc58.10e3c"
           ]
       ]
   },
   {
       "id": "8f2e3d11.a5be9",
       "type": "change",
       "z": "2b47cf3c.1f345",
       "name": "",
       "rules": [
           {
               "t": "set",
               "p": "storedcount",
               "pt": "global",
               "to": "payload",
               "tot": "msg"
           }
       ],
       "action": "",
       "property": "",
       "from": "",
       "to": "",
       "reg": false,
       "x": 1220,
       "y": 280,
       "wires": [
           []
       ]
   },
   {
       "id": "124c5f9c.d6611",
       "type": "change",
       "z": "2b47cf3c.1f345",
       "name": "",
       "rules": [
           {
               "t": "set",
               "p": "tripcount",
               "pt": "global",
               "to": "count",
               "tot": "msg"
           }
       ],
       "action": "",
       "property": "",
       "from": "",
       "to": "",
       "reg": false,
       "x": 1210,
       "y": 340,
       "wires": [
           []
       ]
   },
   {
       "id": "9c2759d5.b48758",
       "type": "function",
       "z": "2b47cf3c.1f345",
       "name": "Add Trip to Stored",
       "func": "var storedcount = global.get(\"storedcount\");\nvar tripcount = global.get(\"tripcount\");\nmsg.payload = storedcount + tripcount;\nreturn msg;",
       "outputs": 1,
       "noerr": 0,
       "x": 510,
       "y": 360,
       "wires": [
           [
               "5e63e3aa.5962ec"
           ]
       ]
   },
   {
       "id": "bd85cdb9.dd59f",
       "type": "inject",
       "z": "2b47cf3c.1f345",
       "name": "Reset Counters",
       "topic": "",
       "payload": "0",
       "payloadType": "num",
       "repeat": "",
       "crontab": "",
       "once": false,
       "x": 140,
       "y": 660,
       "wires": [
           [
               "e3808594.7ac418"
           ]
       ]
   },
   {
       "id": "a88657f9.7eceb8",
       "type": "inject",
       "z": "2b47cf3c.1f345",
       "name": "Initialise Counters",
       "topic": "",
       "payload": "1",
       "payloadType": "num",
       "repeat": "",
       "crontab": "",
       "once": true,
       "x": 130,
       "y": 200,
       "wires": [
           [
               "57ff78a4.fb80f8"
           ]
       ]
   },
   {
       "id": "230fa1c0.55187e",
       "type": "mqtt in",
       "z": "2b47cf3c.1f345",
       "name": "Eng ON",
       "topic": "EngineOn1Switch",
       "qos": "2",
       "broker": "b1d0c3fc.a6fad",
       "x": 70,
       "y": 300,
       "wires": [
           [
               "a80a6965.7e2a58"
           ]
       ]
   },
   {
       "id": "a80a6965.7e2a58",
       "type": "function",
       "z": "2b47cf3c.1f345",
       "name": "Strg to Nbr",
       "func": "msg.payload = Number(msg.payload);\nmsg.topic = \"\";\nreturn msg;",
       "outputs": 1,
       "noerr": 0,
       "x": 210,
       "y": 300,
       "wires": [
           [
               "5b511c3d.d31514",
               "f29f885f.276d88"
           ]
       ]
   },
   {
       "id": "f29f885f.276d88",
       "type": "switch",
       "z": "2b47cf3c.1f345",
       "name": "",
       "property": "payload",
       "propertyType": "msg",
       "rules": [
           {
               "t": "eq",
               "v": "1",
               "vt": "num"
           },
           {
               "t": "eq",
               "v": "0",
               "vt": "num"
           }
       ],
       "checkall": "true",
       "outputs": 2,
       "x": 370,
       "y": 300,
       "wires": [
           [
               "ac105340.cb99c"
           ],
           [
               "9c2759d5.b48758"
           ]
       ]
   },
   {
       "id": "f18b1e29.57f6b",
       "type": "counter",
       "z": "2b47cf3c.1f345",
       "name": "Trip Counter",
       "init": "0",
       "step": "1",
       "lower": null,
       "upper": null,
       "mode": "increment",
       "outputs": "1",
       "x": 1010,
       "y": 420,
       "wires": [
           [
               "124c5f9c.d6611"
           ]
       ]
   },
   {
       "id": "e001a5c0.1b8be8",
       "type": "ui_text",
       "z": "2b47cf3c.1f345",
       "group": "2381998f.63b6d6",
       "order": 6,
       "width": 0,
       "height": 0,
       "name": "",
       "label": "Engine Hrs (Trip)",
       "format": "{{msg.payload}}",
       "layout": "row-spread",
       "x": 670,
       "y": 480,
       "wires": []
   },
   {
       "id": "5e63e3aa.5962ec",
       "type": "key-value-write",
       "z": "2b47cf3c.1f345",
       "store": "964eb4a3.b5f7d8",
       "action": "set",
       "key": "",
       "keyvalue": "",
       "name": "Write to store",
       "x": 690,
       "y": 360,
       "wires": [
           []
       ]
   },
   {
       "id": "ff81fc58.10e3c",
       "type": "function",
       "z": "2b47cf3c.1f345",
       "name": "Reset Trip",
       "func": "msg.reset = true;\nreturn msg;",
       "outputs": 1,
       "noerr": 0,
       "x": 890,
       "y": 320,
       "wires": [
           [
               "f18b1e29.57f6b"
           ]
       ]
   },
   {
       "id": "33bd62f2.6fc79e",
       "type": "change",
       "z": "2b47cf3c.1f345",
       "name": "",
       "rules": [
           {
               "t": "set",
               "p": "storedcount",
               "pt": "global",
               "to": "payload",
               "tot": "msg"
           }
       ],
       "action": "",
       "property": "",
       "from": "",
       "to": "",
       "reg": false,
       "x": 1220,
       "y": 700,
       "wires": [
           []
       ]
   },
   {
       "id": "92d95cd.b9113a",
       "type": "change",
       "z": "2b47cf3c.1f345",
       "name": "",
       "rules": [
           {
               "t": "set",
               "p": "tripcount",
               "pt": "global",
               "to": "payload",
               "tot": "msg"
           }
       ],
       "action": "",
       "property": "",
       "from": "",
       "to": "",
       "reg": false,
       "x": 1210,
       "y": 660,
       "wires": [
           []
       ]
   },
   {
       "id": "57ff78a4.fb80f8",
       "type": "delay",
       "z": "2b47cf3c.1f345",
       "name": "",
       "pauseType": "delay",
       "timeout": "1",
       "timeoutUnits": "seconds",
       "rate": "1",
       "nbRateUnits": "1",
       "rateUnits": "second",
       "randomFirst": "1",
       "randomLast": "5",
       "randomUnits": "seconds",
       "drop": false,
       "x": 440,
       "y": 200,
       "wires": [
           [
               "ac105340.cb99c"
           ]
       ]
   },
   {
       "id": "be88c4f1.d85998",
       "type": "function",
       "z": "2b47cf3c.1f345",
       "name": "Prep Trip Display",
       "func": "var time = global.get(\"tripcount\");\nvar hours = Math.floor(time / 3600);\ntime = time - hours * 3600;\nvar minutes = Math.floor(time / 60);\nvar seconds = time % 60;\nmsg.payload = hours + \"hr \" + minutes + \"m \" + seconds + \"s \";\nreturn msg;",
       "outputs": 1,
       "noerr": 0,
       "x": 370,
       "y": 480,
       "wires": [
           [
               "e001a5c0.1b8be8"
           ]
       ]
   },
   {
       "id": "f4ebe418.011268",
       "type": "function",
       "z": "2b47cf3c.1f345",
       "name": "Prep Total Display",
       "func": "var time = global.get(\"storedcount\") + global.get(\"tripcount\");\nvar hours = Math.floor(time / 3600);\ntime = time - hours * 3600;\nvar minutes = Math.floor(time / 60);\nvar seconds = time % 60;\nmsg.payload = hours + \"hr \" + minutes + \"m \" + seconds + \"s \";\nreturn msg;",
       "outputs": 1,
       "noerr": 0,
       "x": 370,
       "y": 540,
       "wires": [
           [
               "3726e20.932761e"
           ]
       ]
   },
   {
       "id": "2381998f.63b6d6",
       "type": "ui_group",
       "z": "",
       "name": "Col 1",
       "tab": "dae185ad.0bda98",
       "order": 1,
       "disp": false,
       "width": "4"
   },
   {
       "id": "964eb4a3.b5f7d8",
       "type": "key-value-store",
       "z": "",
       "filepath": "store.json",
       "namespace": "",
       "name": "Counter_store"
   },
   {
       "id": "b1d0c3fc.a6fad",
       "type": "mqtt-broker",
       "z": "",
       "broker": "10.10.10.1",
       "port": "1883",
       "clientid": "",
       "usetls": false,
       "compatmode": true,
       "keepalive": "60",
       "cleansession": true,
       "willTopic": "",
       "willQos": "0",
       "willPayload": "",
       "birthTopic": "",
       "birthQos": "0",
       "birthPayload": ""
   },
   {
       "id": "dae185ad.0bda98",
       "type": "ui_tab",
       "z": "",
       "name": "Rpi Performance",
       "icon": "dashboard"
   }
]
(2018-04-23, 06:02 PM)affinite Wrote: [ -> ]Hi all
I've spent a while putting together a Node Red Engine hours flow.
Its not the prettiest thing but I thought I'd share it here for the benefit of other NR newbies like me who are also going down the same path or wanting to implement other timers.

The counter is perpetually stored on Engine OFF so a RPi shutdown wont loose the count.
That said, I've no idea if the store would survive a NodeRed upgrade so Ive included an Inject Node which can be used to Zero the counter or preload an existing Hour Count (don't forget to make a note of the count before doing an NR or OP upgrade !).

In my setup the counter is triggered by an MQTT message generated by a remote sender when the engine is started. The counter is started/stopped with "1" or "0" so easy to modify the start trigger.

Bye the way, before you say it, no I dont time my engine running time to the second but its useful to have seconds ticking when testing and can easily be removed from the display.
 
Cheers

Code:
[
   {
       "id": "3726e20.932761e",
       "type": "ui_text",
       "z": "2b47cf3c.1f345",
       "group": "2381998f.63b6d6",
       "order": 7,
       "width": 0,
       "height": 0,
       "name": "",
       "label": "Engine Hrs (Total)",
       "format": "{{msg.payload}}",
       "layout": "row-spread",
       "x": 670,
       "y": 540,
       "wires": []
   },
   {
       "id": "cbaed108.85542",
       "type": "inject",
       "z": "2b47cf3c.1f345",
       "name": "Ticker",
       "topic": "",
       "payload": "",
       "payloadType": "date",
       "repeat": "1",
       "crontab": "",
       "once": true,
       "x": 160,
       "y": 420,
       "wires": [
           [
               "c3696e78.931fe",
               "be88c4f1.d85998",
               "f4ebe418.011268"
           ]
       ]
   },
   {
       "id": "c3696e78.931fe",
       "type": "function",
       "z": "2b47cf3c.1f345",
       "name": "Send Tick if Eng ON",
       "func": "var engineon = global.get(\"engineon\");\nif (engineon === 0){\n    msg.reset = true;\n}else if (engineon === 1){\n    msg.payload = \"tick\";\n    return msg;\n}",
       "outputs": 1,
       "noerr": 0,
       "x": 380,
       "y": 420,
       "wires": [
           [
               "f18b1e29.57f6b"
           ]
       ]
   },
   {
       "id": "5b511c3d.d31514",
       "type": "change",
       "z": "2b47cf3c.1f345",
       "name": "",
       "rules": [
           {
               "t": "set",
               "p": "engineon",
               "pt": "global",
               "to": "payload",
               "tot": "msg"
           }
       ],
       "action": "",
       "property": "",
       "from": "",
       "to": "",
       "reg": false,
       "x": 410,
       "y": 260,
       "wires": [
           []
       ]
   },
   {
       "id": "e3808594.7ac418",
       "type": "key-value-write",
       "z": "2b47cf3c.1f345",
       "store": "964eb4a3.b5f7d8",
       "action": "set",
       "key": "",
       "keyvalue": "",
       "name": "Write to store",
       "x": 970,
       "y": 660,
       "wires": [
           [
               "33bd62f2.6fc79e",
               "92d95cd.b9113a"
           ]
       ]
   },
   {
       "id": "ac105340.cb99c",
       "type": "key-value-read",
       "z": "2b47cf3c.1f345",
       "store": "964eb4a3.b5f7d8",
       "key": "",
       "name": "Read Store",
       "x": 630,
       "y": 280,
       "wires": [
           [
               "8f2e3d11.a5be9",
               "ff81fc58.10e3c"
           ]
       ]
   },
   {
       "id": "8f2e3d11.a5be9",
       "type": "change",
       "z": "2b47cf3c.1f345",
       "name": "",
       "rules": [
           {
               "t": "set",
               "p": "storedcount",
               "pt": "global",
               "to": "payload",
               "tot": "msg"
           }
       ],
       "action": "",
       "property": "",
       "from": "",
       "to": "",
       "reg": false,
       "x": 1220,
       "y": 280,
       "wires": [
           []
       ]
   },
   {
       "id": "124c5f9c.d6611",
       "type": "change",
       "z": "2b47cf3c.1f345",
       "name": "",
       "rules": [
           {
               "t": "set",
               "p": "tripcount",
               "pt": "global",
               "to": "count",
               "tot": "msg"
           }
       ],
       "action": "",
       "property": "",
       "from": "",
       "to": "",
       "reg": false,
       "x": 1210,
       "y": 340,
       "wires": [
           []
       ]
   },
   {
       "id": "9c2759d5.b48758",
       "type": "function",
       "z": "2b47cf3c.1f345",
       "name": "Add Trip to Stored",
       "func": "var storedcount = global.get(\"storedcount\");\nvar tripcount = global.get(\"tripcount\");\nmsg.payload = storedcount + tripcount;\nreturn msg;",
       "outputs": 1,
       "noerr": 0,
       "x": 510,
       "y": 360,
       "wires": [
           [
               "5e63e3aa.5962ec"
           ]
       ]
   },
   {
       "id": "bd85cdb9.dd59f",
       "type": "inject",
       "z": "2b47cf3c.1f345",
       "name": "Reset Counters",
       "topic": "",
       "payload": "0",
       "payloadType": "num",
       "repeat": "",
       "crontab": "",
       "once": false,
       "x": 140,
       "y": 660,
       "wires": [
           [
               "e3808594.7ac418"
           ]
       ]
   },
   {
       "id": "a88657f9.7eceb8",
       "type": "inject",
       "z": "2b47cf3c.1f345",
       "name": "Initialise Counters",
       "topic": "",
       "payload": "1",
       "payloadType": "num",
       "repeat": "",
       "crontab": "",
       "once": true,
       "x": 130,
       "y": 200,
       "wires": [
           [
               "57ff78a4.fb80f8"
           ]
       ]
   },
   {
       "id": "230fa1c0.55187e",
       "type": "mqtt in",
       "z": "2b47cf3c.1f345",
       "name": "Eng ON",
       "topic": "EngineOn1Switch",
       "qos": "2",
       "broker": "b1d0c3fc.a6fad",
       "x": 70,
       "y": 300,
       "wires": [
           [
               "a80a6965.7e2a58"
           ]
       ]
   },
   {
       "id": "a80a6965.7e2a58",
       "type": "function",
       "z": "2b47cf3c.1f345",
       "name": "Strg to Nbr",
       "func": "msg.payload = Number(msg.payload);\nmsg.topic = \"\";\nreturn msg;",
       "outputs": 1,
       "noerr": 0,
       "x": 210,
       "y": 300,
       "wires": [
           [
               "5b511c3d.d31514",
               "f29f885f.276d88"
           ]
       ]
   },
   {
       "id": "f29f885f.276d88",
       "type": "switch",
       "z": "2b47cf3c.1f345",
       "name": "",
       "property": "payload",
       "propertyType": "msg",
       "rules": [
           {
               "t": "eq",
               "v": "1",
               "vt": "num"
           },
           {
               "t": "eq",
               "v": "0",
               "vt": "num"
           }
       ],
       "checkall": "true",
       "outputs": 2,
       "x": 370,
       "y": 300,
       "wires": [
           [
               "ac105340.cb99c"
           ],
           [
               "9c2759d5.b48758"
           ]
       ]
   },
   {
       "id": "f18b1e29.57f6b",
       "type": "counter",
       "z": "2b47cf3c.1f345",
       "name": "Trip Counter",
       "init": "0",
       "step": "1",
       "lower": null,
       "upper": null,
       "mode": "increment",
       "outputs": "1",
       "x": 1010,
       "y": 420,
       "wires": [
           [
               "124c5f9c.d6611"
           ]
       ]
   },
   {
       "id": "e001a5c0.1b8be8",
       "type": "ui_text",
       "z": "2b47cf3c.1f345",
       "group": "2381998f.63b6d6",
       "order": 6,
       "width": 0,
       "height": 0,
       "name": "",
       "label": "Engine Hrs (Trip)",
       "format": "{{msg.payload}}",
       "layout": "row-spread",
       "x": 670,
       "y": 480,
       "wires": []
   },
   {
       "id": "5e63e3aa.5962ec",
       "type": "key-value-write",
       "z": "2b47cf3c.1f345",
       "store": "964eb4a3.b5f7d8",
       "action": "set",
       "key": "",
       "keyvalue": "",
       "name": "Write to store",
       "x": 690,
       "y": 360,
       "wires": [
           []
       ]
   },
   {
       "id": "ff81fc58.10e3c",
       "type": "function",
       "z": "2b47cf3c.1f345",
       "name": "Reset Trip",
       "func": "msg.reset = true;\nreturn msg;",
       "outputs": 1,
       "noerr": 0,
       "x": 890,
       "y": 320,
       "wires": [
           [
               "f18b1e29.57f6b"
           ]
       ]
   },
   {
       "id": "33bd62f2.6fc79e",
       "type": "change",
       "z": "2b47cf3c.1f345",
       "name": "",
       "rules": [
           {
               "t": "set",
               "p": "storedcount",
               "pt": "global",
               "to": "payload",
               "tot": "msg"
           }
       ],
       "action": "",
       "property": "",
       "from": "",
       "to": "",
       "reg": false,
       "x": 1220,
       "y": 700,
       "wires": [
           []
       ]
   },
   {
       "id": "92d95cd.b9113a",
       "type": "change",
       "z": "2b47cf3c.1f345",
       "name": "",
       "rules": [
           {
               "t": "set",
               "p": "tripcount",
               "pt": "global",
               "to": "payload",
               "tot": "msg"
           }
       ],
       "action": "",
       "property": "",
       "from": "",
       "to": "",
       "reg": false,
       "x": 1210,
       "y": 660,
       "wires": [
           []
       ]
   },
   {
       "id": "57ff78a4.fb80f8",
       "type": "delay",
       "z": "2b47cf3c.1f345",
       "name": "",
       "pauseType": "delay",
       "timeout": "1",
       "timeoutUnits": "seconds",
       "rate": "1",
       "nbRateUnits": "1",
       "rateUnits": "second",
       "randomFirst": "1",
       "randomLast": "5",
       "randomUnits": "seconds",
       "drop": false,
       "x": 440,
       "y": 200,
       "wires": [
           [
               "ac105340.cb99c"
           ]
       ]
   },
   {
       "id": "be88c4f1.d85998",
       "type": "function",
       "z": "2b47cf3c.1f345",
       "name": "Prep Trip Display",
       "func": "var time = global.get(\"tripcount\");\nvar hours = Math.floor(time / 3600);\ntime = time - hours * 3600;\nvar minutes = Math.floor(time / 60);\nvar seconds = time % 60;\nmsg.payload = hours + \"hr \" + minutes + \"m \" + seconds + \"s \";\nreturn msg;",
       "outputs": 1,
       "noerr": 0,
       "x": 370,
       "y": 480,
       "wires": [
           [
               "e001a5c0.1b8be8"
           ]
       ]
   },
   {
       "id": "f4ebe418.011268",
       "type": "function",
       "z": "2b47cf3c.1f345",
       "name": "Prep Total Display",
       "func": "var time = global.get(\"storedcount\") + global.get(\"tripcount\");\nvar hours = Math.floor(time / 3600);\ntime = time - hours * 3600;\nvar minutes = Math.floor(time / 60);\nvar seconds = time % 60;\nmsg.payload = hours + \"hr \" + minutes + \"m \" + seconds + \"s \";\nreturn msg;",
       "outputs": 1,
       "noerr": 0,
       "x": 370,
       "y": 540,
       "wires": [
           [
               "3726e20.932761e"
           ]
       ]
   },
   {
       "id": "2381998f.63b6d6",
       "type": "ui_group",
       "z": "",
       "name": "Col 1",
       "tab": "dae185ad.0bda98",
       "order": 1,
       "disp": false,
       "width": "4"
   },
   {
       "id": "964eb4a3.b5f7d8",
       "type": "key-value-store",
       "z": "",
       "filepath": "store.json",
       "namespace": "",
       "name": "Counter_store"
   },
   {
       "id": "b1d0c3fc.a6fad",
       "type": "mqtt-broker",
       "z": "",
       "broker": "10.10.10.1",
       "port": "1883",
       "clientid": "",
       "usetls": false,
       "compatmode": true,
       "keepalive": "60",
       "cleansession": true,
       "willTopic": "",
       "willQos": "0",
       "willPayload": "",
       "birthTopic": "",
       "birthQos": "0",
       "birthPayload": ""
   },
   {
       "id": "dae185ad.0bda98",
       "type": "ui_tab",
       "z": "",
       "name": "Rpi Performance",
       "icon": "dashboard"
   }
]

I like this! Need to figure out how to get the on/off data from my Penta 2001. How do you do it? I am thinking digital input on a Esp8266. Areally sweet feature would be to be able to automatically add the engine hours to the logbok plugin of OpenCPN
Cheers
Ranur
[attachment=658]

Hi Ranur
Ive attached the config diagram of my ESP8266 which includes the 12v engine ON input that the NodeRed engine timer flow watches.
Ive bench tested it and it works OK. I havent yet tried it on the boat.
Strange - I get an email notification that the thread is updated, but coming here there's nothing...
Sorry - My fault ...
Yesterday I posted an updated flow that uses the new "Hourglass" NR node.
I then found a bug - the timer keeps going if the engine is turned off after the Pi is shut down.
So I deleted the post.
I'll repost when its working Smile
I found that after upgrade to OP2 my Engine Timer flow didnt work so Ive updated it and included the code below.
You will need to install "node-red-contrib-key-value-store" in the NR Palette Manager but all other Nodes are standard.
In my setup, the MQTT/SignalK path "propulsion.state" is sent once a second by the ESP8266 which monitors the engine state. This signal is used to increment the timer.
If you have a constant Engine-On type signal then you'll need to change the flow to incorporate a repeating Injector Node to increment the timer.

(BTW I had to abandon the new "Hourglass" Node as I couldn't find a way to stop it if NR was shutdown with the timer running !)



Code:
[{"id":"a9de4276.efc69","type":"change","z":"4ca2fcda.21eb04","name":"","rules":[{"t":"set","p":"storedcount","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":860,"y":80,"wires":[[]]},{"id":"89efefe.36aac1","type":"ui_text","z":"4ca2fcda.21eb04","group":"7a732336.738eac","order":8,"width":0,"height":0,"name":"","label":"Engine Hrs (Total)","format":"{{msg.payload}}","layout":"row-spread","x":1290,"y":400,"wires":[]},{"id":"ea645186.35d9a","type":"key-value-write","z":"4ca2fcda.21eb04","store":"d5ff438c.f2a6b","action":"set","key":"","keyvalue":"","name":"Write to store","x":650,"y":520,"wires":[["9b6af102.ea62","3935add.e1e5952"]]},{"id":"78f688cf.4b3e48","type":"key-value-read","z":"4ca2fcda.21eb04","store":"193dd33e.5d69ad","key":"","name":"Read Store","x":650,"y":80,"wires":[["a9de4276.efc69"]]},{"id":"a92c0b15.90dc08","type":"inject","z":"4ca2fcda.21eb04","name":"Reset Counters","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"x":480,"y":520,"wires":[["ea645186.35d9a"]]},{"id":"3c32d5a1.42a7ba","type":"mqtt in","z":"4ca2fcda.21eb04","name":"Eng ON","topic":"propulsion.state","qos":"0","datatype":"auto","broker":"2a82cc4c.c89264","x":70,"y":140,"wires":[["275bf305.baefdc"]]},{"id":"6c27818d.c1dd9","type":"switch","z":"4ca2fcda.21eb04","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"num"},{"t":"eq","v":"0","vt":"num"}],"checkall":"true","repair":false,"outputs":2,"x":470,"y":140,"wires":[["78f688cf.4b3e48","f68b2170.8ccf3"],["8e4feba2.55cee8"]]},{"id":"a2699026.64713","type":"ui_text","z":"4ca2fcda.21eb04","group":"7a732336.738eac","order":7,"width":0,"height":0,"name":"","label":"Engine Hrs (Trip)","format":"{{msg.payload}}","layout":"row-spread","x":1290,"y":320,"wires":[]},{"id":"f68b2170.8ccf3","type":"function","z":"4ca2fcda.21eb04","name":"Reset Trip Counter","func":"msg.reset = true;\nreturn msg;","outputs":1,"noerr":0,"x":670,"y":120,"wires":[["42aec02a.5ff0e"]]},{"id":"9b6af102.ea62","type":"change","z":"4ca2fcda.21eb04","name":"","rules":[{"t":"set","p":"storedcount","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":860,"y":580,"wires":[[]]},{"id":"3935add.e1e5952","type":"change","z":"4ca2fcda.21eb04","name":"","rules":[{"t":"set","p":"tripcount","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":850,"y":520,"wires":[[]]},{"id":"1c12756f.7ff62b","type":"function","z":"4ca2fcda.21eb04","name":"Prep Trip Display","func":"var time = global.get(\"tripcount\");\nvar hours = Math.floor(time / 3600);\ntime = time - hours * 3600;\nvar minutes = Math.floor(time / 60);\nvar seconds = time % 60;\nmsg.payload = hours + \"hr \" + minutes + \"m \" + seconds + \"s \";\nreturn msg;","outputs":1,"noerr":0,"x":1070,"y":320,"wires":[["a2699026.64713"]]},{"id":"703a5b8a.5ddb74","type":"function","z":"4ca2fcda.21eb04","name":"Prep Total Display","func":"var time = global.get(\"storedcount\") + global.get(\"tripcount\");\nvar hours = Math.floor(time / 3600);\ntime = time - hours * 3600;\nvar minutes = Math.floor(time / 60);\nvar seconds = time % 60;\nmsg.payload = hours + \"hr \" + minutes + \"m \" + seconds + \"s \";\nreturn msg;","outputs":1,"noerr":0,"x":1070,"y":400,"wires":[["89efefe.36aac1"]]},{"id":"8b58273a.09ce58","type":"rbe","z":"4ca2fcda.21eb04","name":"Once","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":330,"y":140,"wires":[["6c27818d.c1dd9"]],"info":"Only allow the engine on signal through once"},{"id":"a68442e1.79e4d","type":"key-value-write","z":"4ca2fcda.21eb04","store":"193dd33e.5d69ad","action":"set","key":"","keyvalue":"","name":"Write Store","x":1270,"y":200,"wires":[[]]},{"id":"42aec02a.5ff0e","type":"counter","z":"4ca2fcda.21eb04","inc":1,"name":"","x":640,"y":320,"wires":[["26f1a5aa.2ebc7a"]]},{"id":"26f1a5aa.2ebc7a","type":"change","z":"4ca2fcda.21eb04","name":"","rules":[{"t":"set","p":"tripcount","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":850,"y":320,"wires":[["1c12756f.7ff62b"]]},{"id":"6d592bfc.31e7f4","type":"switch","z":"4ca2fcda.21eb04","name":"Only Count \"1\"s","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":360,"y":320,"wires":[["42aec02a.5ff0e","703a5b8a.5ddb74"]]},{"id":"9f66c09c.d61a9","type":"function","z":"4ca2fcda.21eb04","name":"Calc TotalCount","func":"msg.payload = global.get(\"storedcount\") + global.get(\"tripcount\");\nreturn msg;","outputs":1,"noerr":0,"x":1060,"y":200,"wires":[["a68442e1.79e4d"]]},{"id":"66dacabb.53f3d4","type":"inject","z":"4ca2fcda.21eb04","name":"Initialize","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":460,"y":40,"wires":[["78f688cf.4b3e48"]]},{"id":"275bf305.baefdc","type":"function","z":"4ca2fcda.21eb04","name":"S-N","func":"msg.payload = Number(msg.payload);\nmsg.topic = \"\";\nreturn msg;","outputs":1,"noerr":0,"x":190,"y":140,"wires":[["8b58273a.09ce58","6d592bfc.31e7f4"]]},{"id":"8e4feba2.55cee8","type":"delay","z":"4ca2fcda.21eb04","name":"","pauseType":"delay","timeout":"250","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":830,"y":200,"wires":[["9f66c09c.d61a9"]]},{"id":"28f86ffc.a3507","type":"inject","z":"4ca2fcda.21eb04","name":"Initialize","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":460,"y":220,"wires":[["26f1a5aa.2ebc7a"]]},{"id":"4958dabb.1c0f84","type":"inject","z":"4ca2fcda.21eb04","name":"Initialize","topic":"","payload":"storedcount","payloadType":"global","repeat":"","crontab":"","once":true,"onceDelay":"1","x":460,"y":400,"wires":[["703a5b8a.5ddb74"]]},{"id":"7a732336.738eac","type":"ui_group","z":"","name":"Pi Status","tab":"f287220a.330a","order":1,"disp":false,"width":5,"collapse":false},{"id":"d5ff438c.f2a6b","type":"key-value-store","z":"","filepath":"store.json","namespace":"","name":"Counter_store"},{"id":"193dd33e.5d69ad","type":"key-value-store","z":"","filepath":"store.json","namespace":"","name":"Counter_store"},{"id":"2a82cc4c.c89264","type":"mqtt-broker","z":"","broker":"10.10.10.1","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"f287220a.330a","type":"ui_tab","z":"","name":"NavPi Status","icon":"dashboard","order":4,"disabled":false,"hidden":false}]
You could also write the data to an influxdb database.
(2020-05-03, 02:04 PM)PaddyB Wrote: [ -> ]You could also write the data to an influxdb database.

Thats beyond me Paddy - I haven't touched a database since Microsoft Access 20 years ago.

I do like the idea of integrating it with a LogBook so, just for fun, I have added a log function which writes out Engine hours to a text file. /home/pi/NavPi.txt
(If anyone wants to use it, you do need to load the Moment.js Node through Palette manager)

Code:
[{"id":"89efefe.36aac1","type":"ui_text","z":"4ca2fcda.21eb04","group":"7a732336.738eac","order":8,"width":0,"height":0,"name":"","label":"Engine Hrs (Total)","format":"{{msg.payload}}","layout":"row-spread","x":1290,"y":400,"wires":[]},{"id":"ea645186.35d9a","type":"key-value-write","z":"4ca2fcda.21eb04","store":"d5ff438c.f2a6b","action":"set","key":"","keyvalue":"","name":"Write to store","x":610,"y":520,"wires":[["9b6af102.ea62","3935add.e1e5952"]]},{"id":"78f688cf.4b3e48","type":"key-value-read","z":"4ca2fcda.21eb04","store":"193dd33e.5d69ad","key":"","name":"Read Store","x":650,"y":80,"wires":[["a9de4276.efc69"]]},{"id":"a9de4276.efc69","type":"change","z":"4ca2fcda.21eb04","name":"","rules":[{"t":"set","p":"storedcount","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":860,"y":80,"wires":[[]]},{"id":"a92c0b15.90dc08","type":"inject","z":"4ca2fcda.21eb04","name":"Reset Counters","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"x":420,"y":520,"wires":[["ea645186.35d9a"]]},{"id":"3c32d5a1.42a7ba","type":"mqtt in","z":"4ca2fcda.21eb04","name":"Eng ON","topic":"propulsion.state","qos":"0","datatype":"auto","broker":"2a82cc4c.c89264","x":70,"y":140,"wires":[["275bf305.baefdc"]]},{"id":"6c27818d.c1dd9","type":"switch","z":"4ca2fcda.21eb04","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"num"},{"t":"eq","v":"0","vt":"num"}],"checkall":"true","repair":false,"outputs":2,"x":470,"y":140,"wires":[["78f688cf.4b3e48","f68b2170.8ccf3"],["8e4feba2.55cee8"]]},{"id":"a2699026.64713","type":"ui_text","z":"4ca2fcda.21eb04","group":"7a732336.738eac","order":7,"width":0,"height":0,"name":"","label":"Engine Hrs (Trip)","format":"{{msg.payload}}","layout":"row-spread","x":1290,"y":320,"wires":[]},{"id":"f68b2170.8ccf3","type":"function","z":"4ca2fcda.21eb04","name":"Reset Trip Counter","func":"msg.reset = true;\nreturn msg;","outputs":1,"noerr":0,"x":670,"y":120,"wires":[["42aec02a.5ff0e"]]},{"id":"9b6af102.ea62","type":"change","z":"4ca2fcda.21eb04","name":"","rules":[{"t":"set","p":"storedcount","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":860,"y":580,"wires":[[]]},{"id":"3935add.e1e5952","type":"change","z":"4ca2fcda.21eb04","name":"","rules":[{"t":"set","p":"tripcount","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":850,"y":520,"wires":[[]]},{"id":"1c12756f.7ff62b","type":"function","z":"4ca2fcda.21eb04","name":"Prep Trip Display","func":"var time = global.get(\"tripcount\");\nvar hours = Math.floor(time / 3600);\ntime = time - hours * 3600;\nvar minutes = Math.floor(time / 60);\nvar seconds = time % 60;\nmsg.payload = hours + \"hr \" + minutes + \"m \" + seconds + \"s \";\nreturn msg;","outputs":1,"noerr":0,"x":1070,"y":320,"wires":[["a2699026.64713"]]},{"id":"703a5b8a.5ddb74","type":"function","z":"4ca2fcda.21eb04","name":"Prep Total Display","func":"var time = global.get(\"storedcount\") + global.get(\"tripcount\");\nvar hours = Math.floor(time / 3600);\ntime = time - hours * 3600;\nvar minutes = Math.floor(time / 60);\nvar seconds = time % 60;\nmsg.payload = hours + \"hr \" + minutes + \"m \" + seconds + \"s \";\nreturn msg;","outputs":1,"noerr":0,"x":1070,"y":400,"wires":[["89efefe.36aac1"]]},{"id":"8b58273a.09ce58","type":"rbe","z":"4ca2fcda.21eb04","name":"Once","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":330,"y":140,"wires":[["6c27818d.c1dd9"]],"info":"Only allow the engine on signal through once"},{"id":"a68442e1.79e4d","type":"key-value-write","z":"4ca2fcda.21eb04","store":"193dd33e.5d69ad","action":"set","key":"","keyvalue":"","name":"Write to Store","x":1280,"y":200,"wires":[[]]},{"id":"42aec02a.5ff0e","type":"counter","z":"4ca2fcda.21eb04","inc":1,"name":"","x":640,"y":320,"wires":[["26f1a5aa.2ebc7a"]]},{"id":"26f1a5aa.2ebc7a","type":"change","z":"4ca2fcda.21eb04","name":"","rules":[{"t":"set","p":"tripcount","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":850,"y":320,"wires":[["1c12756f.7ff62b"]]},{"id":"6d592bfc.31e7f4","type":"switch","z":"4ca2fcda.21eb04","name":"Only Count \"1\"s","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":380,"y":320,"wires":[["42aec02a.5ff0e","703a5b8a.5ddb74"]]},{"id":"9f66c09c.d61a9","type":"function","z":"4ca2fcda.21eb04","name":"Calc TotalCount","func":"msg.payload = global.get(\"storedcount\") + global.get(\"tripcount\");\nreturn msg;","outputs":1,"noerr":0,"x":1060,"y":200,"wires":[["a68442e1.79e4d","154f8c67.26b974"]]},{"id":"66dacabb.53f3d4","type":"inject","z":"4ca2fcda.21eb04","name":"Initialize","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":400,"y":40,"wires":[["78f688cf.4b3e48"]]},{"id":"275bf305.baefdc","type":"function","z":"4ca2fcda.21eb04","name":"S-N","func":"msg.payload = Number(msg.payload);\nmsg.topic = \"\";\nreturn msg;","outputs":1,"noerr":0,"x":190,"y":140,"wires":[["8b58273a.09ce58","6d592bfc.31e7f4"]]},{"id":"8e4feba2.55cee8","type":"delay","z":"4ca2fcda.21eb04","name":"","pauseType":"delay","timeout":"250","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":810,"y":200,"wires":[["9f66c09c.d61a9"]]},{"id":"28f86ffc.a3507","type":"inject","z":"4ca2fcda.21eb04","name":"Initialize","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":400,"y":220,"wires":[["26f1a5aa.2ebc7a"]]},{"id":"4958dabb.1c0f84","type":"inject","z":"4ca2fcda.21eb04","name":"Initialize","topic":"","payload":"storedcount","payloadType":"global","repeat":"","crontab":"","once":true,"onceDelay":"1","x":400,"y":400,"wires":[["703a5b8a.5ddb74"]]},{"id":"1c66fa5c.3c2a26","type":"file","z":"4ca2fcda.21eb04","name":"Write to Log","filename":"/home/pi/NavPiLog","appendNewline":true,"createDir":false,"overwriteFile":"false","encoding":"none","x":1270,"y":260,"wires":[[]]},{"id":"154f8c67.26b974","type":"function","z":"4ca2fcda.21eb04","name":"Prep Log Entry","func":"var time = global.get (\"tripcount\");\nvar hours = Math.floor(time / 3600);\ntime = time - hours * 3600;\nvar minutes = Math.floor(time / 60);\nvar seconds = time % 60;\nmsg.payload = global.get (\"currenttime\") + \"     Engine off after  \" + hours + \"hr \" + minutes + \"m \" + seconds + \"s \";\nreturn msg;","outputs":1,"noerr":0,"x":1060,"y":260,"wires":[["1c66fa5c.3c2a26"]]},{"id":"de7ef094.e804","type":"moment","z":"4ca2fcda.21eb04","name":"","topic":"","input":"","inputType":"msg","inTz":"Europe/London","adjAmount":"1","adjType":"hours","adjDir":"add","format":"","locale":"en_US","output":"","outputType":"msg","outTz":"Europe/London","x":640,"y":460,"wires":[["8e514736.cbd118"]]},{"id":"9999d265.c8c14","type":"inject","z":"4ca2fcda.21eb04","name":"","topic":"","payload":"","payloadType":"date","repeat":"1","crontab":"","once":true,"onceDelay":"1","x":410,"y":460,"wires":[["de7ef094.e804"]]},{"id":"8e514736.cbd118","type":"change","z":"4ca2fcda.21eb04","name":"","rules":[{"t":"set","p":"currenttime","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":860,"y":460,"wires":[[]]},{"id":"7a732336.738eac","type":"ui_group","z":"","name":"Pi Status","tab":"f287220a.330a","order":1,"disp":false,"width":5,"collapse":false},{"id":"d5ff438c.f2a6b","type":"key-value-store","z":"","filepath":"store.json","namespace":"","name":"Counter_store"},{"id":"193dd33e.5d69ad","type":"key-value-store","z":"","filepath":"store.json","namespace":"","name":"Counter_store"},{"id":"2a82cc4c.c89264","type":"mqtt-broker","z":"","broker":"10.10.10.1","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"f287220a.330a","type":"ui_tab","z":"","name":"NavPi Status","icon":"dashboard","order":4,"disabled":false,"hidden":false}]
(2020-05-03, 07:16 PM)affinite Wrote: [ -> ]
(2020-05-03, 02:04 PM)PaddyB Wrote: [ -> ]You could also write the data to an influxdb database.

Thats beyond me Paddy - I haven't touched a database since Microsoft Access 20 years ago.
It's actually easier than setting up a node red flow in many ways, openplotter will install the database & viewer, a signalk does the writing through an app. You don't need to touch the database other than give it a name, very useful tool to have  Cool
https://openplotter.readthedocs.io/en/la...afana.html