[ { "id": "158e314c.71084f", "type": "tab", "label": "Main Flow", "disabled": false, "info": "" }, { "id": "3df81f27.d1f76", "type": "subflow", "name": "Read Config File", "info": "", "in": [ { "x": 40, "y": 100, "wires": [ { "id": "102caa65.5e8136" } ] } ], "out": [ { "x": 1100, "y": 160, "wires": [ { "id": "19817ca3.d71323", "port": 0 } ] }, { "x": 780, "y": 220, "wires": [ { "id": "abdf15f5.da7a88", "port": 1 } ] } ] }, { "id": "ff451553.56fdc8", "type": "subflow", "name": "Pulse Output", "info": "", "in": [ { "x": 40, "y": 40, "wires": [ { "id": "41047203.dfad6c" }, { "id": "79351d76.b04894" } ] } ], "out": [ { "x": 960, "y": 40, "wires": [ { "id": "3793de77.f6cbe2", "port": 1 } ] } ] }, { "id": "81a5424b.55e1d", "type": "subflow", "name": "Press Stop", "info": "", "in": [ { "x": 200, "y": 100, "wires": [ { "id": "60bd20c6.0025d" } ] } ], "out": [ { "x": 820, "y": 100, "wires": [ { "id": "850355ef.851998", "port": 0 } ] } ] }, { "id": "9abe0d23.0b4f8", "type": "subflow", "name": "Pulse Output (2)", "info": "", "in": [ { "x": 40, "y": 40, "wires": [ { "id": "41047203.dfad6c" }, { "id": "79351d76.b04894" } ] } ], "out": [ { "x": 960, "y": 40, "wires": [ { "id": "3793de77.f6cbe2", "port": 1 } ] } ] }, { "id": "25196831.e307e8", "type": "subflow", "name": "Press Start", "info": "", "in": [ { "x": 140, "y": 40, "wires": [ { "id": "bfb8739.367e79" } ] } ], "out": [ { "x": 620, "y": 40, "wires": [ { "id": "b7028b9d.4d97c8", "port": 0 } ] } ] }, { "id": "9788ac6d.fc8e7", "type": "subflow", "name": "Chart Style", "info": "", "in": [ { "x": 320, "y": 60, "wires": [ { "id": "1c382f60.197ef1" } ] } ], "out": [ { "x": 700, "y": 60, "wires": [ { "id": "1c382f60.197ef1", "port": 0 } ] } ] }, { "id": "a00cfa3a.41f338", "type": "subflow", "name": "Chart", "info": "", "in": [ { "x": 200, "y": 100, "wires": [ { "id": "91d0344.ca14fc8" } ] } ], "out": [ { "x": 620, "y": 100, "wires": [ { "id": "91d0344.ca14fc8", "port": 0 } ] } ] }, { "id": "1314db79.10bc15", "type": "subflow", "name": "Pulse Output (3)", "info": "", "in": [ { "x": 40, "y": 40, "wires": [ { "id": "41047203.dfad6c" }, { "id": "79351d76.b04894" } ] } ], "out": [ { "x": 960, "y": 40, "wires": [ { "id": "3793de77.f6cbe2", "port": 1 } ] } ] }, { "id": "8620b00f.557be", "type": "websocket-listener", "z": "158e314c.71084f", "path": "/treadmill/clock", "wholemsg": "false" }, { "id": "f7b7919.5b9c17", "type": "exec", "z": "3df81f27.d1f76", "command": "ls ", "addpay": true, "append": "", "useSpawn": "", "timer": "", "name": "Checkpassed file is there", "x": 390, "y": 100, "wires": [ [ "abdf15f5.da7a88" ], [], [] ] }, { "id": "abdf15f5.da7a88", "type": "function", "z": "3df81f27.d1f76", "name": "Handle Return", "func": "if (msg.payload !== '')\n {\n msg.filename = flow.get('filename');\n return msg;\n }\nmsg.payload = 1;\nreturn [null,msg];\n", "outputs": "2", "noerr": 0, "x": 580, "y": 200, "wires": [ [ "535f2194.14ff6" ], [] ] }, { "id": "535f2194.14ff6", "type": "file in", "z": "3df81f27.d1f76", "name": "Load Config", "filename": "", "format": "utf8", "x": 810, "y": 160, "wires": [ [ "19817ca3.d71323" ] ] }, { "id": "19817ca3.d71323", "type": "json", "z": "3df81f27.d1f76", "name": "Parse", "x": 990, "y": 160, "wires": [ [] ] }, { "id": "102caa65.5e8136", "type": "function", "z": "3df81f27.d1f76", "name": "Save Filename", "func": "flow.set(\"filename\",msg.payload);\nreturn msg;", "outputs": 1, "noerr": 0, "x": 160, "y": 100, "wires": [ [ "f7b7919.5b9c17" ] ] }, { "id": "a1adac6a.11fc8", "type": "trigger", "z": "1314db79.10bc15", "op1": "0", "op2": "1", "op1type": "num", "op2type": "num", "duration": "100", "extend": false, "units": "ms", "reset": "", "name": "Pulse Length", "x": 410, "y": 340, "wires": [ [ "4e6c6245.26b0ac", "60852ea2.56702" ] ] }, { "id": "35baf0bf.b736e", "type": "function", "z": "1314db79.10bc15", "name": "Counter", "func": "// initialise the counter to 0 if it doesn't exist already\nvar count;\nvar button = global.get(\"buttons\");\nif (msg.payload.count !== undefined)\n {\n count = msg.payload.count;\n global.set(\"btn\",button[msg.payload.button]);\n// if (button !== undefined)\n// node.warn (\"Pressing \" + button[msg.payload.button] + \" \" + msg.payload.count + \" times\");\n\nif (count === 0)\n {\n msg.payload = 1;\n// node.warn(\"Count came in as zero\");\n return [null,msg];\n }\n flow.set('count',count);\n flow.set('pin',msg.payload.button);\n msg.payload = 1;\n }\n\nif (msg.payload === 1) // the pulse ended\n {\n count = flow.get('count');\n// node.warn(\"Getting count \" + count);\n if (count > 0)\n {\n msg.payload = 1;\n count -= 1;\n // store the value back\n flow.set('count',count);\n// node.warn(\"pulsing \" + global.get(\"btn\"));\n return msg;\n }\n else\n {\n // done\n// node.warn(\"Pulsing \" + global.get(\"btn\") + \" done\");\n msg.payload = 1;\n return [null,msg];\n } \n }\n", "outputs": "3", "noerr": 0, "x": 408, "y": 206, "wires": [ [ "24873f6c.7fb12" ], [ "3793de77.f6cbe2" ], [] ] }, { "id": "9c5c0f97.3da11", "type": "delay", "z": "1314db79.10bc15", "name": "Pulse Delay", "pauseType": "delay", "timeout": "100", "timeoutUnits": "milliseconds", "rate": "1", "rateUnits": "second", "randomFirst": "1", "randomLast": "5", "randomUnits": "seconds", "drop": false, "x": 412, "y": 275, "wires": [ [ "31b6e346.0a85fc" ] ] }, { "id": "5e9e4e0b.1b6dc", "type": "switch", "z": "1314db79.10bc15", "name": "", "property": "pin", "propertyType": "flow", "rules": [ { "t": "eq", "v": "40", "vt": "num" }, { "t": "eq", "v": "38", "vt": "num" }, { "t": "eq", "v": "37", "vt": "num" }, { "t": "eq", "v": "36", "vt": "num" }, { "t": "eq", "v": "35", "vt": "num" }, { "t": "eq", "v": "33", "vt": "num" }, { "t": "eq", "v": "32", "vt": "str" } ], "checkall": "true", "outputs": 7, "x": 630, "y": 320, "wires": [ [ "c9aaabe.0c48b58" ], [ "94e8772.0a2ea88" ], [ "3e7dc97e.777246" ], [ "79557b2.fad1e84" ], [ "f57cd800.50f138" ], [ "72b03f04.9ee18" ], [ "b864f721.9d0f28" ] ] }, { "id": "91592364.7cd46", "type": "rpi-gpio out", "z": "1314db79.10bc15", "name": "Incline Up (40/21)", "pin": "40", "set": true, "level": "1", "out": "out", "x": 886, "y": 141, "wires": [] }, { "id": "75ffdd73.f1d3a4", "type": "rpi-gpio out", "z": "1314db79.10bc15", "name": "Incline Down (38/20)", "pin": "38", "set": true, "level": "1", "out": "out", "x": 894, "y": 199, "wires": [] }, { "id": "d5c94ed6.8791c", "type": "rpi-gpio out", "z": "1314db79.10bc15", "name": "Speed Up (37/26)", "pin": "37", "set": true, "level": "1", "out": "out", "x": 886, "y": 261, "wires": [] }, { "id": "ec624d05.ea8fa", "type": "rpi-gpio out", "z": "1314db79.10bc15", "name": "Speed Down (36/16)", "pin": "36", "set": true, "level": "1", "out": "out", "x": 911, "y": 315, "wires": [] }, { "id": "2fef3c40.6968f4", "type": "change", "z": "1314db79.10bc15", "name": "Button Translator", "rules": [ { "t": "change", "p": "payload.button", "pt": "msg", "from": "InclineUp", "fromt": "str", "to": "40", "tot": "num" }, { "t": "change", "p": "payload.button", "pt": "msg", "from": "InclineDown", "fromt": "str", "to": "38", "tot": "num" }, { "t": "change", "p": "payload.button", "pt": "msg", "from": "SpeedUp", "fromt": "str", "to": "37", "tot": "num" }, { "t": "change", "p": "payload.button", "pt": "msg", "from": "SpeedDown", "fromt": "str", "to": "36", "tot": "str" }, { "t": "change", "p": "payload.button", "pt": "msg", "from": "Start", "fromt": "str", "to": "35", "tot": "num" }, { "t": "change", "p": "payload.button", "pt": "msg", "from": "Stop", "fromt": "str", "to": "33", "tot": "str" }, { "t": "change", "p": "payload.button", "pt": "msg", "from": "Pause", "fromt": "str", "to": "32", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 158, "y": 206, "wires": [ [ "31b6e346.0a85fc" ] ] }, { "id": "df966913.ab2738", "type": "rpi-gpio out", "z": "1314db79.10bc15", "name": "Start (35/19)", "pin": "35", "set": true, "level": "1", "out": "out", "x": 869, "y": 376, "wires": [] }, { "id": "60a306a7.a84338", "type": "rpi-gpio out", "z": "1314db79.10bc15", "name": "Stop (33/13)", "pin": "33", "set": true, "level": "1", "out": "out", "x": 866, "y": 432, "wires": [] }, { "id": "d92e28d3.41a6e8", "type": "function", "z": "1314db79.10bc15", "name": "Command Cycler", "func": "var stack;\n//node.warn(\"d1\");\n//node.warn(msg.payload);\n\nif (Array.isArray(msg.payload))\n {\n// node.warn(\"Getting stack\");\n stack = msg.payload; // save the initial stack\n }\nelse\n {\n stack = global.get(\"stack\");\n// node.warn(\"Getting stored stack\");\n }\n\nmsg.payload = stack.shift(); // get the top command of the stack\nif (msg.payload === undefined)\n {\n// node.warn(\"Done Array\");\n msg.payload = 1;\n return [null,msg];\n }\nglobal.set(\"stack\",stack); // save the remaining cmds stack\n//node.warn(\"sending command\");\nreturn [msg,null]; // return the next command", "outputs": "2", "noerr": 0, "x": 530, "y": 20, "wires": [ [ "fbfd91ab.3dc4" ], [] ] }, { "id": "a9990521.96d778", "type": "change", "z": "1314db79.10bc15", "name": "Reset All Relays", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "1", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 600, "y": 100, "wires": [ [ "c9aaabe.0c48b58", "94e8772.0a2ea88", "3e7dc97e.777246", "79557b2.fad1e84", "f57cd800.50f138", "72b03f04.9ee18", "b864f721.9d0f28", "23ebea6d.751356" ] ] }, { "id": "f4234852.59e8c8", "type": "delay", "z": "1314db79.10bc15", "name": "", "pauseType": "delay", "timeout": "250", "timeoutUnits": "milliseconds", "rate": "1", "rateUnits": "second", "randomFirst": "1", "randomLast": "5", "randomUnits": "seconds", "drop": false, "x": 290, "y": 20, "wires": [ [ "3793de77.f6cbe2" ] ] }, { "id": "5642b5c6.2f005c", "type": "rpi-gpio out", "z": "1314db79.10bc15", "name": "Pause 32/12", "pin": "32", "set": true, "level": "1", "out": "out", "x": 880, "y": 500, "wires": [] }, { "id": "167edb66.f1b785", "type": "rpi-gpio out", "z": "1314db79.10bc15", "name": "Relay 8 - 31/6 Unused", "pin": "31", "set": true, "level": "1", "out": "out", "x": 910, "y": 560, "wires": [] }, { "id": "a01512ba.55d36", "type": "debug", "z": "1314db79.10bc15", "name": "", "active": true, "console": "false", "complete": "false", "x": 680, "y": 560, "wires": [] }, { "id": "60bd20c6.0025d", "type": "function", "z": "81a5424b.55e1d", "name": "Press Stop", "func": "msg.payload = [{\"count\":1,\"button\":\"Stop\"}];\nreturn msg;", "outputs": 1, "noerr": 0, "x": 390, "y": 100, "wires": [ [ "850355ef.851998" ] ] }, { "id": "850355ef.851998", "type": "subflow:1314db79.10bc15", "z": "81a5424b.55e1d", "x": 570, "y": 100, "wires": [ [] ] }, { "id": "12d1e8e3.4b88f7", "type": "trigger", "z": "1314db79.10bc15", "op1": "0", "op2": "1", "op1type": "num", "op2type": "num", "duration": "100", "extend": false, "units": "ms", "reset": "", "name": "Pulse Length", "x": 410, "y": 340, "wires": [ [ "4e6c6245.26b0ac", "60852ea2.56702" ] ] }, { "id": "cd327f84.0c51f", "type": "function", "z": "1314db79.10bc15", "name": "Counter", "func": "// initialise the counter to 0 if it doesn't exist already\nvar count;\nvar button = global.get(\"buttons\");\nif (msg.payload.count !== undefined)\n {\n count = msg.payload.count;\n global.set(\"btn\",button[msg.payload.button]);\n// if (button !== undefined)\n// node.warn (\"Pressing \" + button[msg.payload.button] + \" \" + msg.payload.count + \" times\");\n\nif (count === 0)\n {\n msg.payload = 1;\n// node.warn(\"Count came in as zero\");\n return [null,msg];\n }\n flow.set('count',count);\n flow.set('pin',msg.payload.button);\n msg.payload = 1;\n }\n\nif (msg.payload === 1) // the pulse ended\n {\n count = flow.get('count');\n// node.warn(\"Getting count \" + count);\n if (count > 0)\n {\n msg.payload = 1;\n count -= 1;\n // store the value back\n flow.set('count',count);\n// node.warn(\"pulsing \" + global.get(\"btn\"));\n return msg;\n }\n else\n {\n // done\n// node.warn(\"Pulsing \" + global.get(\"btn\") + \" done\");\n msg.payload = 1;\n return [null,msg];\n } \n }\n", "outputs": "3", "noerr": 0, "x": 408, "y": 206, "wires": [ [ "24873f6c.7fb12" ], [ "3793de77.f6cbe2" ], [] ] }, { "id": "1bf37045.02ab3", "type": "delay", "z": "1314db79.10bc15", "name": "Pulse Delay", "pauseType": "delay", "timeout": "100", "timeoutUnits": "milliseconds", "rate": "1", "rateUnits": "second", "randomFirst": "1", "randomLast": "5", "randomUnits": "seconds", "drop": false, "x": 412, "y": 275, "wires": [ [ "31b6e346.0a85fc" ] ] }, { "id": "c49b5eee.24bcb", "type": "switch", "z": "1314db79.10bc15", "name": "", "property": "pin", "propertyType": "flow", "rules": [ { "t": "eq", "v": "40", "vt": "num" }, { "t": "eq", "v": "38", "vt": "num" }, { "t": "eq", "v": "37", "vt": "num" }, { "t": "eq", "v": "36", "vt": "num" }, { "t": "eq", "v": "35", "vt": "num" }, { "t": "eq", "v": "33", "vt": "num" }, { "t": "eq", "v": "32", "vt": "str" } ], "checkall": "true", "outputs": 7, "x": 630, "y": 320, "wires": [ [ "c9aaabe.0c48b58" ], [ "94e8772.0a2ea88" ], [ "3e7dc97e.777246" ], [ "79557b2.fad1e84" ], [ "f57cd800.50f138" ], [ "72b03f04.9ee18" ], [ "b864f721.9d0f28" ] ] }, { "id": "8a53343d.524b08", "type": "rpi-gpio out", "z": "1314db79.10bc15", "name": "Incline Up (40/21)", "pin": "40", "set": true, "level": "1", "out": "out", "x": 886, "y": 141, "wires": [] }, { "id": "c946f9f8.65a968", "type": "rpi-gpio out", "z": "1314db79.10bc15", "name": "Incline Down (38/20)", "pin": "38", "set": true, "level": "1", "out": "out", "x": 894, "y": 199, "wires": [] }, { "id": "377883f2.45a35c", "type": "rpi-gpio out", "z": "1314db79.10bc15", "name": "Speed Up (37/26)", "pin": "37", "set": true, "level": "1", "out": "out", "x": 886, "y": 261, "wires": [] }, { "id": "90ff56ca.37dfc8", "type": "rpi-gpio out", "z": "1314db79.10bc15", "name": "Speed Down (36/16)", "pin": "36", "set": true, "level": "1", "out": "out", "x": 911, "y": 315, "wires": [] }, { "id": "dead5cad.9fea1", "type": "change", "z": "1314db79.10bc15", "name": "Button Translator", "rules": [ { "t": "change", "p": "payload.button", "pt": "msg", "from": "InclineUp", "fromt": "str", "to": "40", "tot": "num" }, { "t": "change", "p": "payload.button", "pt": "msg", "from": "InclineDown", "fromt": "str", "to": "38", "tot": "num" }, { "t": "change", "p": "payload.button", "pt": "msg", "from": "SpeedUp", "fromt": "str", "to": "37", "tot": "num" }, { "t": "change", "p": "payload.button", "pt": "msg", "from": "SpeedDown", "fromt": "str", "to": "36", "tot": "str" }, { "t": "change", "p": "payload.button", "pt": "msg", "from": "Start", "fromt": "str", "to": "35", "tot": "num" }, { "t": "change", "p": "payload.button", "pt": "msg", "from": "Stop", "fromt": "str", "to": "33", "tot": "str" }, { "t": "change", "p": "payload.button", "pt": "msg", "from": "Pause", "fromt": "str", "to": "32", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 158, "y": 206, "wires": [ [ "31b6e346.0a85fc" ] ] }, { "id": "69dc0637.3834c8", "type": "rpi-gpio out", "z": "1314db79.10bc15", "name": "Start (35/19)", "pin": "35", "set": true, "level": "1", "out": "out", "x": 869, "y": 376, "wires": [] }, { "id": "7ad71e57.2fcd2", "type": "rpi-gpio out", "z": "1314db79.10bc15", "name": "Stop (33/13)", "pin": "33", "set": true, "level": "1", "out": "out", "x": 866, "y": 432, "wires": [] }, { "id": "d2656670.dce9f8", "type": "function", "z": "1314db79.10bc15", "name": "Command Cycler", "func": "var stack;\n//node.warn(\"d1\");\n//node.warn(msg.payload);\n\nif (Array.isArray(msg.payload))\n {\n// node.warn(\"Getting stack\");\n stack = msg.payload; // save the initial stack\n }\nelse\n {\n stack = global.get(\"stack\");\n// node.warn(\"Getting stored stack\");\n }\n\nmsg.payload = stack.shift(); // get the top command of the stack\nif (msg.payload === undefined)\n {\n// node.warn(\"Done Array\");\n msg.payload = 1;\n return [null,msg];\n }\nglobal.set(\"stack\",stack); // save the remaining cmds stack\n//node.warn(\"sending command\");\nreturn [msg,null]; // return the next command", "outputs": "2", "noerr": 0, "x": 530, "y": 20, "wires": [ [ "fbfd91ab.3dc4" ], [] ] }, { "id": "e6240bd.b800bf8", "type": "change", "z": "1314db79.10bc15", "name": "Reset All Relays", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "1", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 600, "y": 100, "wires": [ [ "c9aaabe.0c48b58", "94e8772.0a2ea88", "3e7dc97e.777246", "79557b2.fad1e84", "f57cd800.50f138", "72b03f04.9ee18", "b864f721.9d0f28", "23ebea6d.751356" ] ] }, { "id": "5345c053.f7e67", "type": "delay", "z": "1314db79.10bc15", "name": "", "pauseType": "delay", "timeout": "250", "timeoutUnits": "milliseconds", "rate": "1", "rateUnits": "second", "randomFirst": "1", "randomLast": "5", "randomUnits": "seconds", "drop": false, "x": 290, "y": 20, "wires": [ [ "3793de77.f6cbe2" ] ] }, { "id": "37add411.aa815c", "type": "rpi-gpio out", "z": "1314db79.10bc15", "name": "Pause 32/12", "pin": "32", "set": true, "level": "1", "out": "out", "x": 880, "y": 500, "wires": [] }, { "id": "d6225a21.555d78", "type": "rpi-gpio out", "z": "1314db79.10bc15", "name": "Relay 8 - 31/6 Unused", "pin": "31", "set": true, "level": "1", "out": "out", "x": 910, "y": 560, "wires": [] }, { "id": "83d795b8.4128c8", "type": "debug", "z": "1314db79.10bc15", "name": "", "active": true, "console": "false", "complete": "false", "x": 680, "y": 560, "wires": [] }, { "id": "bfb8739.367e79", "type": "function", "z": "25196831.e307e8", "name": "Press Start", "func": "//node.warn(\"Pressing Start\");\nmsg.payload = [{\"count\":1,\"button\":\"Start\"}];\nreturn msg;", "outputs": 1, "noerr": 0, "x": 290, "y": 40, "wires": [ [ "b7028b9d.4d97c8" ] ] }, { "id": "b7028b9d.4d97c8", "type": "subflow:1314db79.10bc15", "z": "25196831.e307e8", "x": 470, "y": 40, "wires": [ [] ] }, { "id": "1c382f60.197ef1", "type": "template", "z": "9788ac6d.fc8e7", "name": "Chart Style", "field": "chartstyle", "fieldType": "msg", "format": "handlebars", "syntax": "mustache", "template": "/* Style Sheet */\n.chartdiv {\n margin: 10px auto;\n width: 95%;\n BORDER: 2px solid #606dad;\n padding: 4px;\n border-radius: 9px;\n background-color: #9196af;\n}\n\n.chartdiv td {\n height: 20px;\n width: 15px;\n}\n\n.chartdiv .whitebox {\n background-color: #ccc;\n }\n \n.chartdiv .selectedwhitebox {\n background-color: #561232;\n }\n \n.chartdiv .speedbox {\n background-color: rgba(158, 53, 16, 0.64);\n}\n\n.chartdiv .inclinebox {\n background-color: rgba(57, 46, 167, 0.69);\n border-right: 2px solid #ccc;\n}\n\n.chartdiv .selectedspeedbox {\n background-color: rgba(158, 53, 16, 1.0);\n}\n\n.chartdiv .selectedinclinebox {\n background-color: rgba(57, 46, 167, 1.0);\n border-right: 2px solid #ccc;\n }\n\n.chartdiv .chartdiv {\n padding: 6px;\n font-weight: bold;\n}\n\n.chartdiv table {\n padding: 10px;\n border: 2px #555 solid;\n background-color: #ccc;\n border-radius: 10px;\n margin: 0 auto;\n width: 95%;\n }\n \n.chartdiv .legend {\n margin: 2px auto;\n border-right: 0;\n font-weight: bold;\n color: white;\n width: 100px;\n text-align: center;\n }\n \n.chartdiv .programtitle {\n font-size: 16px;\n font-weight: bold;\n padding-left: 10px;\n }", "x": 530, "y": 60, "wires": [ [] ] }, { "id": "91d0344.ca14fc8", "type": "function", "z": "a00cfa3a.41f338", "name": "Chart Generator", "func": "context.global.createChart = function(programno,currentstep,selected)\n {\n html = \"\";\n var speed = 0;\n var include = 0;\n var col;\n programno = parseInt(programno);\n if (currentstep === undefined)\n currentstep = -1;\n var program = global.get(\"programs\")[programno];\n// node.warn(\"Program: \" + programno);\n html += \"
\";\n html += \"
\";\n if (selected !== undefined)\n {\n html += \"
\";\n html += \" \" : \"> \"; \n html += \"\";\n html += \"
\";\n }\n else\n {\n html += \"Program \" + (programno + 1) + \" - \" + program.name;\n }\n html += \"
\";\n html += \"
\";\n html += \"';\n\n for (var row=4; row>=0; row--)\n {\n html += \"\";\n for (col=0; col < global.get(\"timesteps\"); col++)\n {\n //node.warn(program[col]);\n if (program[col] !== undefined)\n {\n speed = program[col].speed;\n incline = program[col].incline;\n }\n //node.warn(\"Speed:\" + speed + \" Incline:\" + incline);\n speedclass = row >= speed ? \"whitebox\" : \n col<=currentstep?\"selectedspeedbox\": \"speedbox\";\n inclineclass = row >= incline ? \"whitebox\" :\n col<=currentstep?\"selectedinclinebox\": \"inclinebox\";\n html += \"\\n\"; \n html += \"\\n\"; \n }\n html += \"\\n\";\n }\n html += \"\"; // OUTPUT THE BASELINE ELEMENTS\n for (col=0; col < global.get(\"timesteps\"); col++)\n {\n speedclass = col<=currentstep?\"selectedspeedbox\": \"speedbox\";\n inclineclass = col<=currentstep?\"selectedinclinebox\": \"inclinebox\";\n html += \"\\n\"; \n html += \"\\n\"; \n }\n html += \"\\n\";\n html += \"
\";\n return html;\n }\n \nreturn msg;\n\n", "outputs": 1, "noerr": 0, "x": 410, "y": 100, "wires": [ [] ] }, { "id": "24873f6c.7fb12", "type": "trigger", "z": "1314db79.10bc15", "op1": "0", "op2": "1", "op1type": "num", "op2type": "num", "duration": "100", "extend": false, "units": "ms", "reset": "", "name": "Pulse Length", "x": 410, "y": 340, "wires": [ [ "4e6c6245.26b0ac", "60852ea2.56702" ] ] }, { "id": "31b6e346.0a85fc", "type": "function", "z": "1314db79.10bc15", "name": "Counter", "func": "// initialise the counter to 0 if it doesn't exist already\nvar count;\nvar button = global.get(\"buttons\");\nif (msg.payload.count !== undefined)\n {\n count = msg.payload.count;\n global.set(\"btn\",button[msg.payload.button]);\n// if (button !== undefined)\n// node.warn (\"Pressing \" + button[msg.payload.button] + \" \" + msg.payload.count + \" times\");\n\nif (count === 0)\n {\n msg.payload = 1;\n// node.warn(\"Count came in as zero\");\n return [null,msg];\n }\n flow.set('count',count);\n flow.set('pin',msg.payload.button);\n msg.payload = 1;\n }\n\nif (msg.payload === 1) // the pulse ended\n {\n count = flow.get('count');\n// node.warn(\"Getting count \" + count);\n if (count > 0)\n {\n msg.payload = 1;\n count -= 1;\n // store the value back\n flow.set('count',count);\n// node.warn(\"pulsing \" + global.get(\"btn\"));\n return msg;\n }\n else\n {\n // done\n// node.warn(\"Pulsing \" + global.get(\"btn\") + \" done\");\n msg.payload = 1;\n return [null,msg];\n } \n }\n", "outputs": "3", "noerr": 0, "x": 408, "y": 206, "wires": [ [ "24873f6c.7fb12" ], [ "3793de77.f6cbe2" ], [] ] }, { "id": "60852ea2.56702", "type": "delay", "z": "1314db79.10bc15", "name": "Pulse Delay", "pauseType": "delay", "timeout": "100", "timeoutUnits": "milliseconds", "rate": "1", "rateUnits": "second", "randomFirst": "1", "randomLast": "5", "randomUnits": "seconds", "drop": false, "x": 412, "y": 275, "wires": [ [ "31b6e346.0a85fc" ] ] }, { "id": "4e6c6245.26b0ac", "type": "switch", "z": "1314db79.10bc15", "name": "", "property": "pin", "propertyType": "flow", "rules": [ { "t": "eq", "v": "40", "vt": "num" }, { "t": "eq", "v": "38", "vt": "num" }, { "t": "eq", "v": "37", "vt": "num" }, { "t": "eq", "v": "36", "vt": "num" }, { "t": "eq", "v": "35", "vt": "num" }, { "t": "eq", "v": "33", "vt": "num" }, { "t": "eq", "v": "32", "vt": "str" } ], "checkall": "true", "outputs": 7, "x": 630, "y": 320, "wires": [ [ "c9aaabe.0c48b58" ], [ "94e8772.0a2ea88" ], [ "3e7dc97e.777246" ], [ "79557b2.fad1e84" ], [ "f57cd800.50f138" ], [ "72b03f04.9ee18" ], [ "b864f721.9d0f28" ] ] }, { "id": "c9aaabe.0c48b58", "type": "rpi-gpio out", "z": "1314db79.10bc15", "name": "Incline Up (40/21)", "pin": "40", "set": true, "level": "1", "out": "out", "x": 886, "y": 141, "wires": [] }, { "id": "94e8772.0a2ea88", "type": "rpi-gpio out", "z": "1314db79.10bc15", "name": "Incline Down (38/20)", "pin": "38", "set": true, "level": "1", "out": "out", "x": 894, "y": 199, "wires": [] }, { "id": "3e7dc97e.777246", "type": "rpi-gpio out", "z": "1314db79.10bc15", "name": "Speed Up (37/26)", "pin": "37", "set": true, "level": "1", "out": "out", "x": 886, "y": 261, "wires": [] }, { "id": "79557b2.fad1e84", "type": "rpi-gpio out", "z": "1314db79.10bc15", "name": "Speed Down (36/16)", "pin": "36", "set": true, "level": "1", "out": "out", "x": 911, "y": 315, "wires": [] }, { "id": "fbfd91ab.3dc4", "type": "change", "z": "1314db79.10bc15", "name": "Button Translator", "rules": [ { "t": "change", "p": "payload.button", "pt": "msg", "from": "InclineUp", "fromt": "str", "to": "40", "tot": "num" }, { "t": "change", "p": "payload.button", "pt": "msg", "from": "InclineDown", "fromt": "str", "to": "38", "tot": "num" }, { "t": "change", "p": "payload.button", "pt": "msg", "from": "SpeedUp", "fromt": "str", "to": "37", "tot": "num" }, { "t": "change", "p": "payload.button", "pt": "msg", "from": "SpeedDown", "fromt": "str", "to": "36", "tot": "str" }, { "t": "change", "p": "payload.button", "pt": "msg", "from": "Start", "fromt": "str", "to": "35", "tot": "num" }, { "t": "change", "p": "payload.button", "pt": "msg", "from": "Stop", "fromt": "str", "to": "33", "tot": "str" }, { "t": "change", "p": "payload.button", "pt": "msg", "from": "Pause", "fromt": "str", "to": "32", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 158, "y": 206, "wires": [ [ "31b6e346.0a85fc" ] ] }, { "id": "f57cd800.50f138", "type": "rpi-gpio out", "z": "1314db79.10bc15", "name": "Start (35/19)", "pin": "35", "set": true, "level": "1", "out": "out", "x": 869, "y": 376, "wires": [] }, { "id": "72b03f04.9ee18", "type": "rpi-gpio out", "z": "1314db79.10bc15", "name": "Stop (33/13)", "pin": "33", "set": true, "level": "1", "out": "out", "x": 866, "y": 432, "wires": [] }, { "id": "3793de77.f6cbe2", "type": "function", "z": "1314db79.10bc15", "name": "Command Cycler", "func": "var stack;\n//node.warn(\"d1\");\n//node.warn(msg.payload);\n\nif (Array.isArray(msg.payload))\n {\n// node.warn(\"Getting stack\");\n stack = msg.payload; // save the initial stack\n }\nelse\n {\n stack = global.get(\"stack\");\n// node.warn(\"Getting stored stack\");\n }\n\nmsg.payload = stack.shift(); // get the top command of the stack\nif (msg.payload === undefined)\n {\n// node.warn(\"Done Array\");\n msg.payload = 1;\n return [null,msg];\n }\nglobal.set(\"stack\",stack); // save the remaining cmds stack\n//node.warn(\"sending command\");\nreturn [msg,null]; // return the next command", "outputs": "2", "noerr": 0, "x": 530, "y": 20, "wires": [ [ "fbfd91ab.3dc4" ], [] ] }, { "id": "79351d76.b04894", "type": "change", "z": "1314db79.10bc15", "name": "Reset All Relays", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "1", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 600, "y": 100, "wires": [ [ "c9aaabe.0c48b58", "94e8772.0a2ea88", "3e7dc97e.777246", "79557b2.fad1e84", "f57cd800.50f138", "72b03f04.9ee18", "b864f721.9d0f28", "23ebea6d.751356" ] ] }, { "id": "41047203.dfad6c", "type": "delay", "z": "1314db79.10bc15", "name": "", "pauseType": "delay", "timeout": "250", "timeoutUnits": "milliseconds", "rate": "1", "rateUnits": "second", "randomFirst": "1", "randomLast": "5", "randomUnits": "seconds", "drop": false, "x": 290, "y": 20, "wires": [ [ "3793de77.f6cbe2" ] ] }, { "id": "b864f721.9d0f28", "type": "rpi-gpio out", "z": "1314db79.10bc15", "name": "Pause 32/12", "pin": "32", "set": true, "level": "1", "out": "out", "x": 880, "y": 500, "wires": [] }, { "id": "23ebea6d.751356", "type": "rpi-gpio out", "z": "1314db79.10bc15", "name": "Relay 8 - 31/6 Unused", "pin": "31", "set": true, "level": "1", "out": "out", "x": 910, "y": 560, "wires": [] }, { "id": "f4ca549.6ae83a8", "type": "debug", "z": "1314db79.10bc15", "name": "", "active": true, "console": "false", "complete": "false", "x": 680, "y": 560, "wires": [] }, { "id": "f006fdf5.d8fe", "type": "subflow:1314db79.10bc15", "z": "158e314c.71084f", "x": 360, "y": 1000, "wires": [ [ "96a4ae77.b42a" ] ] }, { "id": "2144e37e.ca249c", "type": "http response", "z": "158e314c.71084f", "name": "web out", "x": 1230, "y": 1000, "wires": [] }, { "id": "4f1d7e35.ad794", "type": "subflow:1314db79.10bc15", "z": "158e314c.71084f", "x": 360, "y": 1200, "wires": [ [ "fb2a07d1.a00918" ] ] }, { "id": "c02abd9c.1e652", "type": "subflow:1314db79.10bc15", "z": "158e314c.71084f", "x": 351, "y": 1139, "wires": [ [ "aea37578.fb03f8" ] ] }, { "id": "80e9d7df.b56c98", "type": "subflow:1314db79.10bc15", "z": "158e314c.71084f", "x": 360, "y": 1260, "wires": [ [ "9b326b13.9a5a38" ] ] }, { "id": "ed1f2d9a.4ddb6", "type": "http in", "z": "158e314c.71084f", "name": "", "url": "/treadmill", "method": "get", "swaggerDoc": "", "x": 60, "y": 60, "wires": [ [ "801f68a8.a14248", "72da95d9.3e3f1c" ] ] }, { "id": "9342013c.b3891", "type": "template", "z": "158e314c.71084f", "name": "Form", "field": "payload", "fieldType": "msg", "format": "handlebars", "syntax": "mustache", "template": "\n\n \n Treadmill Programmer\n \n \n \n \n
\n
\n
\n

Treadmill Program

\n
\n
Time:
{{{time}}} minutes
\n
\n
Weight:
{{{weight}}} lbs
\n
\n
Speed Min:
{{{minspeed}}} mph
\n
\n
Speed Max:
{{{maxspeed}}} mph
\n
\n
Incline Min:
{{{minincline}}} degrees
\n
\n
Incline Max:
{{{maxincline}}} degrees
\n
\n \n
Current User:
{{{usernamelist}}}
\n
\n
Save As Name:
{{{newusername}}}
\n
\n
\n \n
\n
\n
\n
\n {{{tables}}}\n {{{legend}}}\n
\n
\n
\n \n {{{script}}}\n \n\n", "x": 880, "y": 400, "wires": [ [ "f0efec4d.34d8" ] ] }, { "id": "f0efec4d.34d8", "type": "http response", "z": "158e314c.71084f", "name": "", "x": 1020, "y": 400, "wires": [] }, { "id": "71819a22.7f00f4", "type": "http in", "z": "158e314c.71084f", "name": "", "url": "/treadmill/storeandgo", "method": "post", "swaggerDoc": "", "x": 100, "y": 764, "wires": [ [ "50622682.881788" ] ] }, { "id": "97bf980c.f74958", "type": "file", "z": "158e314c.71084f", "name": "Save Config", "filename": "", "appendNewline": true, "createDir": false, "overwriteFile": "true", "x": 620, "y": 840, "wires": [] }, { "id": "ad073d06.f485e", "type": "function", "z": "158e314c.71084f", "name": "Set Weight", "func": "//node.warn(\"Setting weight\");\nvar weight = global.get(\"weight\") - global.get(\"initialweight\");\nif (weight >= 0)\n msg.payload = [{\"count\":weight,\"button\":\"SpeedUp\"}];\nelse if (weight < 0)\n msg.payload = [{\"count\":-weight,\"button\":\"SpeedDown\"}];\nreturn msg;", "outputs": 1, "noerr": 0, "x": 140, "y": 1200, "wires": [ [ "4f1d7e35.ad794" ] ] }, { "id": "e4f341a3.8951b", "type": "function", "z": "158e314c.71084f", "name": "Set Time", "func": "//node.warn(\"Setting time\");\nvar time = global.get(\"time\") - global.get(\"initialtime\");\nif (time > 0)\n msg.payload = [{\"count\":time+2,\"button\":\"SpeedUp\"}];\nelse if (time < 0)\n msg.payload = [{\"count\":-time-2,\"button\":\"SpeedDown\"}];\nelse\n msg.payload = [];\nreturn msg;", "outputs": 1, "noerr": 0, "x": 130, "y": 1260, "wires": [ [ "80e9d7df.b56c98" ] ] }, { "id": "ba13f105.7b13", "type": "template", "z": "158e314c.71084f", "name": "Script", "field": "script", "fieldType": "msg", "format": "handlebars", "syntax": "mustache", "template": "\n", "x": 740, "y": 400, "wires": [ [ "9342013c.b3891" ] ] }, { "id": "595309a.d8821f8", "type": "comment", "z": "158e314c.71084f", "name": "Display Setup Form", "info": "", "x": 1180, "y": 400, "wires": [] }, { "id": "eeb9e4b4.8651d8", "type": "comment", "z": "158e314c.71084f", "name": "Store Settings", "info": "Save the settings to a file and set the globals", "x": 920, "y": 800, "wires": [] }, { "id": "8031992a.67e118", "type": "comment", "z": "158e314c.71084f", "name": "Initialize Treadmill", "info": "", "x": 780, "y": 1180, "wires": [] }, { "id": "e7f57b5c.872088", "type": "template", "z": "158e314c.71084f", "name": "Form", "field": "payload", "fieldType": "msg", "format": "handlebars", "syntax": "mustache", "template": "\n\n \n Treadmill Programmer\n \n \n {{{chartparams}}}\n {{{googlechart}}}\n \n \n
\n
\n

Treadmill Program

\n
Initializing Treadmill
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n \n \n
\n
\n \n
\n
\n
\n \n \n\n", "x": 1080, "y": 1000, "wires": [ [ "2144e37e.ca249c" ] ] }, { "id": "3649d594.261e0a", "type": "template", "z": "158e314c.71084f", "name": "Script", "field": "script", "fieldType": "msg", "format": "handlebars", "syntax": "mustache", "template": " var ws;\n var wsUri = \"ws:\";\n var loc = window.location;\n console.log(loc);\n if (loc.protocol === \"https:\") { wsUri = \"wss:\"; }\n // This needs to point to the web socket in the Node-RED flow\n\n wsUri += \"//\" + loc.host + loc.pathname.replace(\"storeandgo\",\"clock\");\n\n function wsConnect() {\n //console.log(\"connect\",wsUri);\n ws = new WebSocket(wsUri);\n //console.log(Object.getOwnPropertyNames(WebSocket));\n //var line = \"\"; // either uncomment this for a building list of messages\n ws.onmessage = function(msg) {\n // parse the incoming message as a JSON object\n // console.log(msg);\n var message=JSON.parse(msg.data);\n var textmsg = message[0];\n var graph = message[1];\n var msgtype = message[2];\n if (message[3] != null)\n {\n if (message[3].time != null)\n {\n var time = message[3].time;\n chartdata0.setValue(0, 1, time);\n chart0.draw(chartdata0, chartoptions0);\n }\n if (message[3].secsleft != null)\n {\n var secsleft = message[3].secsleft;\n chartdata3.setValue(0, 1, secsleft);\n chart3.draw(chartdata3, chartoptions3);\n }\n if (message[3].speed != null)\n {\n var speed = message[3].speed;\n chartdata1.setValue(0, 1, speed);\n chart1.draw(chartdata1, chartoptions1);\n }\n if (message[3].incline != null)\n {\n var incline = message[3].incline;\n chartdata2.setValue(0, 1, incline);\n chart2.draw(chartdata2, chartoptions2);\n }\n }\n //console.log(message);\n // build the output from the topic and payload parts of the object\n // replace the messages div with the new \"line\"\n if (textmsg != null)\n document.getElementById('messages').innerHTML = textmsg;\n if (graph != null)\n document.getElementById('graph').innerHTML = graph;\n switch (msgtype)\n {\n case \"chart\": \n document.getElementById('stopbutton').setAttribute(\"style\",\"display:block\");\n document.getElementById('pausebutton').setAttribute(\"style\",\"display:block\");\n document.getElementById('resumebutton').setAttribute(\"style\",\"display:none\");\n break;\n case \"endchart\": \n/* document.getElementById('stopbutton').setAttribute(\"style\",\"display:none\");\n document.getElementById('pausebutton').setAttribute(\"style\",\"display:none\");\n document.getElementById('resumebutton').setAttribute(\"style\",\"display:none\");\n document.getElementById('restartbutton').setAttribute(\"style\",\"display:block\");\n*/\n document.getElementById('buttons').setAttribute(\"style\",\"display:none\");\n document.getElementById('restart').setAttribute(\"style\",\"display:block\");\n break;\n case \"pause\":\n document.getElementById('resumebutton').setAttribute(\"style\",\"display:block\");\n document.getElementById('pausebutton').setAttribute(\"style\",\"display:none\");\n break;\n case \"resume\":\n document.getElementById('resumebutton').setAttribute(\"style\",\"display:none\");\n document.getElementById('pausebutton').setAttribute(\"style\",\"display:block\");\n break;\n case 'hidepause':\n document.getElementById('pausebutton').disabled = true;\n break;\n case 'showpause':\n document.getElementById('pausebutton').disabled = false;\n break;\n\n case null:\n default:\n break;\n }\n \n //ws.send(JSON.stringify({data:data}));\n }\n ws.onopen = function() {\n // update the status div with the connection status\n // document.getElementById('status').innerHTML = \"connected\";\n //ws.send(\"Open for data\");\n console.log(\"connected\");\n }\n ws.onclose = function() {\n // update the status div with the connection status\n // document.getElementById('status').innerHTML = \"not connected\";\n // in case of lost connection tries to reconnect every 3 secs\n setTimeout(wsConnect,3000);\n }\n }\n \n function closeSocket()\n {\n ws = null;\n }\n \n function restart()\n {\n window.location.href = '/treadmill';\n }\n \n function doit(type) {\n if (ws) { \n ws.send(type); \n }\n }\n ", "x": 940, "y": 1000, "wires": [ [ "e7f57b5c.872088" ] ] }, { "id": "7b5d806e.d25a4", "type": "template", "z": "158e314c.71084f", "name": "Style", "field": "style", "fieldType": "msg", "format": "handlebars", "syntax": "mustache", "template": "/* Style Sheet */\n\n#page {\n width: 930px;\n /*margin: 0 auto;*/\n}\n\n \n.area { \n font-family: arial;\n width: 930px;\n background-color: #bcbcbc;\n border-radius: 15px;\n margin: 0 auto 10px;\n padding: 12px;\n color: #444;\n}\n\n.area h1 {\n text-align: center;\n}\n\n.area .clear {\n clear: both;\n}\n\n#gauges {\n text-align: center;\n}\n\n#gaugesbox {\n display: inline-block;\n}\n\n#gauges .gauge {\n float: left;\n}\n\n#buttons, #restart {\n height: 160px;\n width: 90%;\n margin: 0 auto;\n}\n\n#stopbutton { \n display: none; \n float: left;\n}\n\n#restart { \n display: none;\n text-align: center;\n}\n\n#restartbutton { \n \n}\n\n#pausebutton, #resumebutton {\n display: none; \n float: right;\n}\n\n#resumebutton { \n background: #00dd00;\n border: solid #00aa00 4px;\n}\n\n#resumebutton:hover {\n cursor: pointer; \n background: #00ff00;\n}\n\n#pausebutton { \n background: #f7b35d;\n border: solid #FF8F00 4px;\n}\n\n#pausebutton:hover {\n cursor: pointer;\n background: #ff9b1c;\n}\n\n#pausebutton:disabled { \n cursor: default; \n background: #777;\n border: solid #444 4px;\n}\n\n\n.msg {\n font-size: 26px;\n text-align:center;\n font-weight: bold;\n padding-top: 3px;\n margin: 0 auto;\n color: red;\n }\n \n.btn {\n -webkit-border-radius: 28;\n -moz-border-radius: 28;\n border-radius: 28px;\n font-family: Arial;\n color: #ffffff;\n font-size: 60px;\n background: #b53838;\n padding: 40px 35px 40px 35px;\n border: solid #ff0022 4px;\n text-decoration: none;\n width: 350px;\n}\n\n.btn:hover {\n cursor: pointer;\n background: #ff0000;\n text-decoration: none;\n}", "x": 740, "y": 900, "wires": [ [ "b0be1a45.9e43f8" ] ] }, { "id": "327331de.6a3d2e", "type": "websocket out", "z": "158e314c.71084f", "name": "", "server": "8620b00f.557be", "client": "", "x": 1240, "y": 1260, "wires": [] }, { "id": "c918da3.97d8328", "type": "function", "z": "158e314c.71084f", "name": "Set Globals", "func": "\nglobal.set(\"initialweight\",150);\nglobal.set(\"initialtime\",20);\nglobal.set(\"timesteps\",20);\nglobal.set(\"speedsteps\",1); // Tenth of a MPH\nglobal.set(\"maxspeed\",100); // Tenth of a MPH\nglobal.set(\"minspeed\",5); // Tenth of a MPH\nglobal.set(\"inclinesteps\",5); // Tenth of a Degrees\nglobal.set(\"maxincline\",150); // Tenth of a Degrees\nglobal.set(\"minincline\",0); // Tenth of a Degrees\nglobal.set(\"minutetosecs\",60); // this should be 60 in production\nglobal.set(\"running\",false);\nif (msg.payload.maxspeedunits === undefined)\n {\n msg.payload = { \n \"minspeedunits\":'0',\n \"minspeedtenths\":'5',\n \"maxspeedunits\":'1',\n \"maxspeedtenths\":'5',\n \"mininclineunits\":'0', \n \"mininclinetenths\":'0', \n \"maxinclineunits\":'1', \n \"maxinclinetenths\":'0', \n \"weight\":'150', \n \"time\":'20',\n \"username\":'',\n \"newusername\":'',\n \"program\":'0'\n };\n }\n \nvar buttons = {40:\"SpeedUp\",\n 38:\"SpeedDown\",\n 37:\"InclineUp\",\n 36:\"InclineDown\",\n 35:\"Start\",\n 33:\"Stop\",\n 32:\"Pause\"};\nglobal.set(\"buttons\",buttons);\n\n// Missing indices will use the previous defined index\nvar programs = {\n 0: {\n \"name\":\"Fat Burning\",\n 0:{\"speed\":2,\"incline\":0},\n 1:{\"speed\":4,\"incline\":1},\n 2:{\"speed\":5,\"incline\":2},\n 3:{\"speed\":3,\"incline\":3},\n 4:{\"speed\":3,\"incline\":4},\n 6:{\"speed\":3,\"incline\":5},\n 7:{\"speed\":3,\"incline\":3},\n 8:{\"speed\":4,\"incline\":0},\n 10:{\"speed\":5,\"incline\":0},\n 11:{\"speed\":5,\"incline\":3},\n 12:{\"speed\":5,\"incline\":4},\n 13:{\"speed\":4,\"incline\":4},\n 14:{\"speed\":4,\"incline\":5},\n 15:{\"speed\":3,\"incline\":4},\n 16:{\"speed\":3,\"incline\":3},\n 17:{\"speed\":5,\"incline\":2},\n 18:{\"speed\":2,\"incline\":0},\n 19:{\"speed\":0,\"incline\":0}\n },\n 1: {\n \"name\":\"Intermediate\",\n 0:{\"speed\":2,\"incline\":0},\n 1:{\"speed\":3,\"incline\":1},\n 2:{\"speed\":4,\"incline\":2},\n 3:{\"speed\":5,\"incline\":3},\n 4:{\"speed\":4,\"incline\":5},\n 6:{\"speed\":4,\"incline\":1},\n 7:{\"speed\":5,\"incline\":3},\n 9:{\"speed\":4,\"incline\":1},\n 10:{\"speed\":5,\"incline\":5},\n 12:{\"speed\":4,\"incline\":1},\n 13:{\"speed\":3,\"incline\":3},\n 15:{\"speed\":4,\"incline\":1},\n 16:{\"speed\":4,\"incline\":4},\n 17:{\"speed\":4,\"incline\":3},\n 18:{\"speed\":3,\"incline\":2},\n 19:{\"speed\":2,\"incline\":1}\n },\n 2: {\n \"name\":\"Advanced\",\n 0:{\"speed\":1,\"incline\":0},\n 1:{\"speed\":2,\"incline\":0},\n 2:{\"speed\":5,\"incline\":1},\n 3:{\"speed\":4,\"incline\":2},\n 4:{\"speed\":4,\"incline\":3},\n 5:{\"speed\":4,\"incline\":4},\n 6:{\"speed\":4,\"incline\":5},\n 7:{\"speed\":3,\"incline\":5},\n 8:{\"speed\":3,\"incline\":4},\n 9:{\"speed\":4,\"incline\":3},\n 10:{\"speed\":4,\"incline\":3},\n 11:{\"speed\":4,\"incline\":4},\n 12:{\"speed\":4,\"incline\":5},\n 13:{\"speed\":3,\"incline\":5},\n 14:{\"speed\":3,\"incline\":4},\n 15:{\"speed\":4,\"incline\":3},\n 16:{\"speed\":4,\"incline\":2},\n 17:{\"speed\":5,\"incline\":1},\n 18:{\"speed\":2,\"incline\":0},\n 19:{\"speed\":1,\"incline\":0}\n },\n 3: {\n \"name\":\"Intervals\",\n 0:{\"speed\":1,\"incline\":0},\n 1:{\"speed\":2,\"incline\":1},\n 2:{\"speed\":3,\"incline\":2},\n 3:{\"speed\":5,\"incline\":5},\n 4:{\"speed\":3,\"incline\":0},\n 5:{\"speed\":5,\"incline\":5},\n 6:{\"speed\":3,\"incline\":0},\n 7:{\"speed\":5,\"incline\":5},\n 8:{\"speed\":3,\"incline\":0},\n 9:{\"speed\":5,\"incline\":5},\n 10:{\"speed\":3,\"incline\":0},\n 11:{\"speed\":5,\"incline\":5},\n 12:{\"speed\":3,\"incline\":0},\n 13:{\"speed\":5,\"incline\":5},\n 14:{\"speed\":3,\"incline\":0},\n 15:{\"speed\":5,\"incline\":5},\n 16:{\"speed\":3,\"incline\":0},\n 17:{\"speed\":5,\"incline\":5},\n 18:{\"speed\":2,\"incline\":1},\n 19:{\"speed\":1,\"incline\":0}\n },\n 4: {\n \"name\":\"Recommended by md.com\",\n 0:{\"speed\":0,\"incline\":0},\n 1:{\"speed\":2,\"incline\":0},\n 2:{\"speed\":3,\"incline\":0},\n 3:{\"speed\":4,\"incline\":1},\n 5:{\"speed\":4,\"incline\":3},\n 8:{\"speed\":5,\"incline\":5},\n 9:{\"speed\":4,\"incline\":3},\n 11:{\"speed\":5,\"incline\":5},\n 12:{\"speed\":4,\"incline\":3},\n 14:{\"speed\":5,\"incline\":5},\n 15:{\"speed\":4,\"incline\":3},\n 17:{\"speed\":3,\"incline\":1},\n 18:{\"speed\":2,\"incline\":0},\n 19:{\"speed\":1,\"incline\":0}\n } /*,\n 5: {\n \"name\":\"test\",\n 0:{\"speed\":5,\"incline\":5},\n 1:{\"speed\":0,\"incline\":0},\n 2:{\"speed\":1,\"incline\":1},\n 3:{\"speed\":2,\"incline\":2},\n 4:{\"speed\":3,\"incline\":3},\n 5:{\"speed\":4,\"incline\":4},\n 6:{\"speed\":5,\"incline\":5},\n 7:{\"speed\":0,\"incline\":0}\n }*/\n };\nglobal.set(\"programs\",programs);\nreturn msg;", "outputs": 1, "noerr": 0, "x": 620, "y": 300, "wires": [ [ "d92a4798.6bd818" ] ] }, { "id": "c4ac2c4e.127c1", "type": "function", "z": "158e314c.71084f", "name": "Set Globals", "func": "global.set('running',true);\nglobal.set('stop',0);\nglobal.set('pause',0);\nglobal.set(\"weight\",msg.payload.weight);\nglobal.set(\"time\",msg.payload.time);\nglobal.set(\"program\",msg.payload.program);\nglobal.set(\"usermaxspeed\",(parseInt(msg.payload.maxspeedunits)*10) + parseInt(msg.payload.maxspeedtenths));\nglobal.set(\"usermaxincline\",(parseInt(msg.payload.maxinclineunits)*10) + parseInt(msg.payload.maxinclinetenths));\nglobal.set(\"userminspeed\",Math.max(global.get('minspeed'),(parseInt(msg.payload.minspeedunits)*10) + parseInt(msg.payload.minspeedtenths)));\nglobal.set(\"userminincline\",(parseInt(msg.payload.mininclineunits)*10) + parseInt(msg.payload.mininclinetenths));\nreturn msg;", "outputs": 1, "noerr": 0, "x": 400, "y": 900, "wires": [ [ "73484767.ef4d48", "47fc360f.1591c8" ] ] }, { "id": "7a270187.c9df5", "type": "function", "z": "158e314c.71084f", "name": "Program Processor", "func": "var currentSpeed = 0;\nvar currentIncline = 0;\nvar program = global.get(\"programs\")[global.get(\"program\")];\nif (program === undefined)\n {\n global.set(\"program\",0);\n program = global.get(\"programs\")[global.get(\"program\")];\n }\nvar speedSteps = (global.get(\"usermaxspeed\") - global.get(\"userminspeed\"))/5; \nvar inclineSteps = (global.get(\"usermaxincline\") - global.get(\"userminincline\"))/25; \n//node.warn('Speed steps: ' + speedSteps);\n//node.warn('Incline steps: ' + inclineSteps);\nfunction setSpeed(speed)\n {\n speed *= speedSteps;\n speed = Math.round(speed);\n var pulses = speed - currentSpeed;\n currentSpeed = speed;\n if (pulses > 0)\n {\n // do speed up\n return {\"count\":pulses,\"button\":\"SpeedUp\"};\n }\n else if (pulses < 0)\n {\n // do speed down\n return {\"count\":-pulses,\"button\":\"SpeedDown\"};\n }\n return null;\n }\nfunction setIncline(incline)\n {\n incline *= inclineSteps;\n incline = Math.round(incline);\n var pulses = incline - currentIncline;\n currentIncline = incline;\n if (pulses > 0)\n {\n // do incline up\n return {\"count\":pulses,\"button\":\"InclineUp\"};\n }\n else if (pulses < 0)\n {\n // do incline down\n return {\"count\":-pulses,\"button\":\"InclineDown\"};\n }\n return null;\n }\n \n function setSpeedAndIncline(speed,incline) {\n var cmd = [];\n var newspeed = setSpeed(speed);\n if (newspeed !== null)\n cmd.push(newspeed);\n var newincline = setIncline(incline);\n if (newincline !== null)\n cmd.push(newincline);\n msg.payload = cmd;\n node.send([null,msg]);\n }\n\n\nvar currentstep = 0;\nvar maxsteps = global.get(\"timesteps\");\nvar timePeriod = (global.get(\"time\") * global.get(\"minutetosecs\")) / maxsteps;\nvar seconds = -1;\nvar period = timePeriod;\n\n//node.warn(\"timeperiod \" + timePeriod);\n//dostep(true);\ncontext.global.timerId = setInterval(dostep,1000);\n\nfunction dostep()\n {\n if (global.get(\"pause\") == 1)\n return;\n var data = [];\n seconds++;\n var mins = Number(seconds/60).toFixed(2);\n// node.warn(\"Minutes:\" + mins);\n if (seconds % timePeriod !== 0)\n {\n data[0] = null;\n data[1] = null;\n data[2] = null;\n data[3] = {\"time\":mins,\"secsleft\":period,\"speed\":null,\"incline\":null};\n node.send([{\"payload\":JSON.stringify(data)},null]);\n if (--period === 0)\n period = timePeriod;\n return;\n }\n// node.warn(\"Doing step \" + currentstep);\n var stop = global.get('stop');\n // node.warn(\"Stop \" + stop);\n if (currentstep == maxsteps || stop == 1)\n {\n if (stop === 0)\n {\n data[0] = \"
Program Ended
\";\n data[1] = context.global.createChart(global.get(\"program\"));\n data[2] = \"endchart\";\n data[3] = {\"time\":0,\"speed\":0,\"secsleft\":0,\"incline\":0};\n msg.payload = [{\"count\":1,\"button\":\"Stop\"}];\n node.send([{\"payload\":JSON.stringify(data)},msg]);\n }\n clearInterval(context.global.timerId);\n return;\n }\n \n\n if (program[currentstep] !== undefined)\n {\n setSpeedAndIncline(program[currentstep].speed,program[currentstep].incline);\n }\n var realSpeed = (Math.round((currentSpeed * global.get(\"speedsteps\")) + global.get(\"userminspeed\")))/10;\n// node.warn(realSpeed + ' ' + currentSpeed + ' ' + global.get(\"userminspeed\") + ' ' + global.get(\"speedsteps\")); \n var realIncline = (Math.round((currentIncline * global.get(\"inclinesteps\"))) + global.get(\"userminincline\"))/10;\n// node.warn(realIncline + ' ' + currentIncline + ' ' + global.get(\"userminincline\") + ' ' + global.get(\"inclinesteps\")); \n data[0] = \"
Program Running
\";\n data[1] = context.global.createChart(global.get(\"program\"),currentstep);\n data[2] = \"chart\";\n data[3] = {\"time\":mins,\"secsleft\":period,\"speed\":realSpeed,\"incline\":realIncline};\n var payload = JSON.stringify(data);\n currentstep++;\n if (--period === 0)\n period = timePeriod;\n node.send([{payload:payload},null]);\n }\n", "outputs": "2", "noerr": 0, "x": 960, "y": 1420, "wires": [ [ "1b44da52.c02e96" ], [ "cda23fd3.a79b2" ] ] }, { "id": "d38771af.59018", "type": "subflow:a00cfa3a.41f338", "z": "158e314c.71084f", "name": "Chart", "x": 920, "y": 300, "wires": [ [ "1fffa6c8.217719" ] ] }, { "id": "7027323.8f9cecc", "type": "template", "z": "158e314c.71084f", "name": "Style", "field": "style", "fieldType": "msg", "format": "handlebars", "syntax": "mustache", "template": "/* Style Sheet */\n.btnbox {\n text-align: center;\n margin: 10px;\n }\n \n.btn {\n -webkit-border-radius: 28px;\n -moz-border-radius: 28px;\n border-radius: 28px;\n font-family: Arial;\n color: #ffffff;\n font-size: 60px;\n background: #b53838;\n padding: 40px 35px 40px 35px;\n border: solid #ff0022 4px;\n text-decoration: none;\n display: inline-block;\n width: 350px;\n}\n\n.smallbtn {\n -webkit-border-radius: 8px;\n -moz-border-radius: 8px;\n border-radius: 8px;\n font-family: Arial;\n color: #ffffff;\n font-size: 16px !important;\n background: #b53838 !important;\n padding: 2px;\n border: solid #ff0022 2px;\n text-decoration: none;\n display: inline-block;\n}\n\n.btn:hover, .smallbtn:hover {\n background: #ff0000 !important;\n cursor: pointer;\n text-decoration: none;\n}\n\n#page {\n width: 930px;\n /* margin: 0 auto; */\n}\n\n.area { \n font-family: arial;\n width: 930px;\n background-color: #bcbcbc;\n border-radius: 15px;\n margin: 0 auto 10px;\n padding: 12px;\n color: #444;\n}\n\n.area h1 {\n text-align: center;\n}\n\n#form {\n/* width: 80%; */\n margin: 0 auto;\n}\n\n.elemField {\n font-size: 24px;\n}\n\n.elemField select, .elemField input {\n float: left;\n font-size: 20px;\n background-color: #fff28f;\n margin: 0 4px 0 0;\n}\n\n.elemTitle {\n float: left;\n width: 450px;\n text-align: right;\n padding: 4px 0;\n font-size: 24px;\n}\n\n#chartarea {\n}\n\n.clear {\n clear: both;\n}\n\n/* hide input */\ninput.radio:empty {\n\t/*margin-left: -999px;*/\n\tdisplay: none;\n}\n\n\nlabel {\n width: 450px;\n border-radius: 3px;\n border: 0px solid #D1D3D4\n}\n\n/* style label */\ninput.radio:empty ~ label {\n\tposition: relative;\n\tfloat: left;\n\tline-height: 20px;\n\ttext-indent: 3.25em;\n\tmargin-bottom: 6px;\n\tcursor: pointer;\n\t-webkit-user-select: none;\n\t-moz-user-select: none;\n\t-ms-user-select: none;\n\tuser-select: none;\n\tcolor: #5d5757;\n}\n\ninput.radio:empty ~ label:before {\n\tposition: absolute;\n\tdisplay: block;\n\ttop: 0;\n\tbottom: 0;\n\tleft: 0;\n\tcontent: '';\n\twidth: 2.5em;\n\tbackground: #D1D3D4;\n\tborder-radius: 3px;\n}\n\n/* toggle hover */\ninput.radio:hover:not(:checked) ~ label:before {\n\tcontent:'\\2714';\n\ttext-indent: .9em;\n\tcolor: #ff0000;\n}\n\ninput.radio:hover:not(:checked) ~ label {\n\tcolor: #ff0000;\n}\n\n/* toggle on */\ninput.radio:checked ~ label:before {\n\tcontent:'\\2714';\n\ttext-indent: .9em;\n\tcolor: #9CE2AE;\n\tbackground-color: #4DCB6D;\n}\n\ninput.radio:checked ~ label {\n\tcolor: #333;\n}\n\n/* radio focus */\ninput.radio:focus ~ label:before {\n\tbox-shadow: 0 0 0 2px #999;\n}", "x": 600, "y": 400, "wires": [ [ "ba13f105.7b13" ] ] }, { "id": "81f53f59.1d757", "type": "function", "z": "158e314c.71084f", "name": "Program Form Elements", "func": "var selected;\nvar programs = global.get(\"programs\");\nvar programcount = Object.keys(programs).length;\n\nmsg.legend = \"
Speed
\";\nmsg.legend += \"
Incline
\";\nmsg.tables = '';\nif (msg.payload.program === undefined)\n msg.payload.program = 0;\nfor (programno = 0; programno < programcount; programno++)\n {\n msg.tables += context.global.createChart(programno,global.get(\"timesteps\"),\n programno == msg.payload.program); \n }\n\nfunction padtitle(title,count) {\n var pad = '';\n if (count === undefined)\n count = 2;\n for (var i=0; i < count; i++)\n pad += \" \"\n return pad + title + pad;\n }\n \nmsg.weight = \"\";\n \n // Now do time selector\nmsg.time = \"\";\n \n // Now do user name selector\n\nmsg.usernamelist = \"\";\n//if (msg.payload.names.length)\n// msg.usernamelist += \"
\";\n\nmsg.newusername = \"
\";\n\n// Now do Max/Min selects\n\n// Min Speed Units\nmsg.minspeed = \"\";\n\n// Min Speed Tenths\nmsg.minspeed += \"\";\n\n// Max Speed Units\n\nmsg.maxspeed = \"\";\n\n// Max Speed Tenths\nmsg.maxspeed += \"\";\n\n// Min Incline Units\nmsg.minincline = \"\";\n\n// Min Incline Tenths\nmsg.minincline += \"\";\n\n// Max Incline Units\nmsg.maxincline = \"\";\n\n// Max Incline Tenths\nmsg.maxincline += \"\";\nreturn msg;", "outputs": 1, "noerr": 0, "x": 400, "y": 400, "wires": [ [ "7027323.8f9cecc" ] ] }, { "id": "1fffa6c8.217719", "type": "subflow:9788ac6d.fc8e7", "z": "158e314c.71084f", "x": 1060, "y": 300, "wires": [ [ "81f53f59.1d757" ] ] }, { "id": "73484767.ef4d48", "type": "subflow:9788ac6d.fc8e7", "z": "158e314c.71084f", "x": 590, "y": 900, "wires": [ [ "7b5d806e.d25a4" ] ] }, { "id": "47fc360f.1591c8", "type": "function", "z": "158e314c.71084f", "name": "Stop", "func": "msg.payload = [{\"count\":2,\"button\":\"Stop\"}];\nreturn msg;", "outputs": 1, "noerr": 0, "x": 220, "y": 1000, "wires": [ [ "f006fdf5.d8fe" ] ] }, { "id": "8d75fdf2.fccd7", "type": "function", "z": "158e314c.71084f", "name": "Select Manual Program", "func": "msg.payload = [{\"count\":1,\"button\":\"SpeedDown\"}]\nreturn msg;", "outputs": 1, "noerr": 0, "x": 140, "y": 1140, "wires": [ [ "c02abd9c.1e652" ] ] }, { "id": "aea37578.fb03f8", "type": "subflow:25196831.e307e8", "z": "158e314c.71084f", "x": 540, "y": 1140, "wires": [ [ "ad073d06.f485e" ] ] }, { "id": "fb2a07d1.a00918", "type": "subflow:25196831.e307e8", "z": "158e314c.71084f", "x": 550, "y": 1200, "wires": [ [ "e4f341a3.8951b" ] ] }, { "id": "4ebd43fb.fbd4ac", "type": "subflow:25196831.e307e8", "z": "158e314c.71084f", "x": 120, "y": 1420, "wires": [ [ "29817444.21675c" ] ] }, { "id": "be1120cf.dd1e8", "type": "comment", "z": "158e314c.71084f", "name": "Output Progress Screen", "info": "", "x": 1230, "y": 1040, "wires": [] }, { "id": "da5f0ba.14de9f8", "type": "template", "z": "158e314c.71084f", "name": "Google Chart API", "field": "googlechart", "fieldType": "msg", "format": "handlebars", "syntax": "mustache", "template": "\n\n ", "x": 1120, "y": 900, "wires": [ [ "3649d594.261e0a" ] ] }, { "id": "9b326b13.9a5a38", "type": "function", "z": "158e314c.71084f", "name": "Start Countdown", "func": "var wait = 8;\nvar data = [];\ndata[0] = \"
Starting in \" + wait +\" seconds
\";\ndata[1] = context.global.createChart(global.get(\"program\"));\ndata[2] = \"chart\";\ndata[3] = {\"step\":0,\"speed\":0,\"incline\":0};\nvar payload = JSON.stringify(data);\nnode.send([null,{payload:payload}]);\n\nvar timerId = setInterval(docountdown,1000);\n\nfunction docountdown()\n {\n stop = global.get('stop');\n if (stop != 1)\n {\n data[0] = \"
Starting in \" + wait +\" seconds
\";\n data[1] = null;\n data[2] = null;\n data[3] = null;\n var payload = JSON.stringify(data);\n node.send([null,{payload:payload}]);\n }\n \n if (stop != 1 && wait == 3) // start the treadmill\n node.send([msg,null]);\n\n if (wait === 0 || stop == 1)\n {\n clearInterval(timerId);\n// node.warn(\"Ending wait\");\n } \n \n wait--;\n }", "outputs": "2", "noerr": 0, "x": 560, "y": 1260, "wires": [ [ "4ebd43fb.fbd4ac" ], [ "327331de.6a3d2e" ] ] }, { "id": "50622682.881788", "type": "switch", "z": "158e314c.71084f", "name": "Already Running", "property": "running", "propertyType": "global", "rules": [ { "t": "true" }, { "t": "false" } ], "checkall": "false", "outputs": 2, "x": 120, "y": 864, "wires": [ [ "ba54ef32.5ce5f", "5d60f031.3c7c1" ], [ "c4ac2c4e.127c1", "e4b14181.8705a" ] ] }, { "id": "cedc864e.274508", "type": "subflow:81a5424b.55e1d", "z": "158e314c.71084f", "x": 560, "y": 700, "wires": [ [] ] }, { "id": "a9318e60.e8e7b", "type": "http response", "z": "158e314c.71084f", "name": "/treadmill", "x": 560, "y": 740, "wires": [] }, { "id": "ba54ef32.5ce5f", "type": "template", "z": "158e314c.71084f", "name": "Redirect", "field": "payload", "fieldType": "msg", "format": "handlebars", "syntax": "mustache", "template": "", "x": 380, "y": 740, "wires": [ [ "a9318e60.e8e7b" ] ] }, { "id": "4f734e81.b7574", "type": "comment", "z": "158e314c.71084f", "name": "Stop Treadmill and Redirect", "info": "", "x": 770, "y": 740, "wires": [] }, { "id": "5d60f031.3c7c1", "type": "function", "z": "158e314c.71084f", "name": "Stop Program", "func": "clearInterval(context.global.timerId);\nglobal.set(\"stop\",1);\nreturn msg;", "outputs": 1, "noerr": 0, "x": 380, "y": 700, "wires": [ [ "cedc864e.274508" ] ] }, { "id": "29817444.21675c", "type": "delay", "z": "158e314c.71084f", "name": "Wait for treadmill countdown", "pauseType": "delay", "timeout": "4", "timeoutUnits": "seconds", "rate": "1", "rateUnits": "second", "randomFirst": "1", "randomLast": "5", "randomUnits": "seconds", "drop": false, "x": 330, "y": 1420, "wires": [ [ "bb5ef6c6.28bac8" ] ] }, { "id": "b0be1a45.9e43f8", "type": "function", "z": "158e314c.71084f", "name": "Gauges Parameter", "func": "msg.time = msg.payload.time;\nmsg.ticks = \"\";\nvar majorTicks = 5;\nif (timePeriod/majorTicks > 10)\n majorTicks += 5;\nfor (var incr=0; incr <= msg.time; incr += majorTicks)\n {\n if (msg.ticks.length > 0)\n msg.ticks += ',';\n msg.ticks += incr;\n }\nmsg.ticks = '[' + msg.ticks + ']';\nmsg.minorticks = 5;\nmsg.minspeed = global.get(\"userminspeed\")/10;\nmsg.minincline = global.get(\"userminincline\")/10;\nmsg.maxspeed = global.get(\"usermaxspeed\")/10;\nmsg.maxincline = global.get(\"usermaxincline\")/10;\n\nvar time = global.get(\"time\");\nvar timePeriod = (global.get(\"time\") * global.get(\"minutetosecs\")) / global.get(\"timesteps\");\nvar secsleftscales =\n {\n 15:{\"major\":\"[0,5,10,15,20,25,30,35,40,45]\",\"minor\":5},\n 20:{\"major\":\"[0,5,10,15,20,25,30,35,40,45,50,55,60]\",\"minor\":5},\n 25:{\"major\":\"[0,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75]\",\"minor\":5},\n 30:{\"major\":\"[0,10,20,30,40,50,60,70,80,90]\",\"minor\":5},\n 35:{\"major\":\"[0,15,30,45,60,75,90,105]\",\"minor\":5},\n 40:{\"major\":\"[0,20,40,60,80,100,120]\",\"minor\":10},\n 45:{\"major\":\"[0,15,30,45,60,75,90,105,120,135]\",\"minor\":3},\n 50:{\"major\":\"[0,30,60,90,120,150]\",\"minor\":6},\n 55:{\"major\":\"[0,15,30,45,60,75,90,105,120,135,150,165]\",\"minor\":3},\n 60:{\"major\":\"[0,30,60,90,120,150,180]\",\"minor\":6}\n };\n\n\nmsg.secsleftmajorticks = secsleftscales[time].major;\nmsg.secsleftminorticks = secsleftscales[time].minor;\nmsg.secsleftmax = timePeriod;\nreturn msg;", "outputs": 1, "noerr": 0, "x": 900, "y": 900, "wires": [ [ "da5f0ba.14de9f8" ] ] }, { "id": "72da95d9.3e3f1c", "type": "exec", "z": "158e314c.71084f", "command": "ls -1 ~/.node-red/lib/flows/treadmill/users", "addpay": false, "append": "", "useSpawn": "", "timer": "", "name": "Get User List", "x": 240, "y": 20, "wires": [ [ "7d914628.205a48" ], [], [] ] }, { "id": "d92a4798.6bd818", "type": "join", "z": "158e314c.71084f", "name": "", "mode": "custom", "build": "merged", "property": "payload", "propertyType": "msg", "key": "payload", "joiner": "\\n", "timeout": "", "count": "2", "x": 780, "y": 300, "wires": [ [ "d38771af.59018" ] ] }, { "id": "7d914628.205a48", "type": "function", "z": "158e314c.71084f", "name": "Parse names", "func": "var names = msg.payload.replace(/\\n+/g,' ');\nnames = names.trim();\nnames = names.split(\" \");\nmsg.payload = {\"names\":names};\nreturn msg;", "outputs": 1, "noerr": 0, "x": 600, "y": 20, "wires": [ [ "d92a4798.6bd818" ] ] }, { "id": "e4b14181.8705a", "type": "function", "z": "158e314c.71084f", "name": "Save User Settings", "func": "var newuser = msg.payload.newusername.trim();\nvar currentuser = msg.payload.username;\nmsg.payload.newusername = ''; \nif (parseInt(msg.payload.minspeedunits) === 0 && parseInt(msg.payload.minspeedtenths) < global.get('minspeed'))\n msg.payload.minspeedtenths = '' + global.get('minspeed') + '';\n\nvar filenamebase = \"/home/pi/.node-red/lib/flows/treadmill/\"; \nif (newuser.length) // if there's a new user name defined save it\n {\n newuser = newuser.toLowerCase();\n newuser = newuser[0].toUpperCase() + newuser.slice(1);\n msg.filename = filenamebase + \"users/\" + newuser; \n msg.payload.username = newuser;\n node.send([msg,null]);\n }\nelse if (currentuser.length)\n {\n msg.filename = filenamebase + \"users/\" + currentuser;\n node.send([msg,null]);\n }\nmsg.filename = filenamebase + \"treadmill.cfg\"; \nreturn [null,msg];\n", "outputs": "2", "noerr": 0, "x": 400, "y": 820, "wires": [ [ "26e12c93.906484" ], [ "97bf980c.f74958" ] ] }, { "id": "26e12c93.906484", "type": "file", "z": "158e314c.71084f", "name": "Save User Config", "filename": "", "appendNewline": true, "createDir": false, "overwriteFile": "true", "x": 640, "y": 780, "wires": [] }, { "id": "3e63460d.0a6aca", "type": "switch", "z": "158e314c.71084f", "name": "User Defined?", "property": "payload.username", "propertyType": "msg", "rules": [ { "t": "neq", "v": "''", "vt": "str" }, { "t": "else" } ], "checkall": "true", "outputs": 2, "x": 470, "y": 160, "wires": [ [ "c918da3.97d8328" ], [ "c6b5c65.34ad638" ] ] }, { "id": "c6b5c65.34ad638", "type": "function", "z": "158e314c.71084f", "name": "Build User Filename", "func": "var currentuser = msg.payload.username;\nmsg.payload = \"/home/pi/.node-red/lib/flows/treadmill/users/\" + currentuser; \nreturn msg;", "outputs": 1, "noerr": 0, "x": 150, "y": 300, "wires": [ [ "b48e9919.9a09a8" ] ] }, { "id": "801f68a8.a14248", "type": "function", "z": "158e314c.71084f", "name": "Set Base Config filename", "func": "msg.payload = \"/home/pi/.node-red/lib/flows/treadmill/treadmill.cfg\";\nreturn msg;", "outputs": 1, "noerr": 0, "x": 280, "y": 80, "wires": [ [ "bc30f777.1302f8" ] ] }, { "id": "bc30f777.1302f8", "type": "subflow:3df81f27.d1f76", "z": "158e314c.71084f", "x": 260, "y": 160, "wires": [ [ "3e63460d.0a6aca" ], [ "c918da3.97d8328" ] ] }, { "id": "b48e9919.9a09a8", "type": "subflow:3df81f27.d1f76", "z": "158e314c.71084f", "x": 360, "y": 300, "wires": [ [ "c918da3.97d8328" ], [ "c918da3.97d8328" ] ] }, { "id": "cb54f3bb.8e9b", "type": "debug", "z": "158e314c.71084f", "name": "", "active": true, "console": "false", "complete": "false", "x": 1480, "y": 1300, "wires": [] }, { "id": "33c200ce.f3234", "type": "http in", "z": "158e314c.71084f", "name": "", "url": "/treadmill/ajax", "method": "post", "swaggerDoc": "", "x": 110, "y": 480, "wires": [ [ "c3994341.c0128" ] ] }, { "id": "c3994341.c0128", "type": "function", "z": "158e314c.71084f", "name": "Make Settings Flename", "func": "msg.payload = \"/home/pi/.node-red/lib/flows/treadmill/users/\" + msg.payload.filename;\nreturn msg;", "outputs": 1, "noerr": 0, "x": 340, "y": 480, "wires": [ [ "af4ea642.1544c8" ] ] }, { "id": "af4ea642.1544c8", "type": "subflow:3df81f27.d1f76", "z": "158e314c.71084f", "x": 560, "y": 480, "wires": [ [ "19348e2b.4a7ec2" ], [] ] }, { "id": "e0493a19.3f6e58", "type": "http response", "z": "158e314c.71084f", "name": "", "x": 1020, "y": 480, "wires": [] }, { "id": "19348e2b.4a7ec2", "type": "change", "z": "158e314c.71084f", "name": "", "rules": [ { "t": "set", "p": "payload.success", "pt": "msg", "to": "true", "tot": "bool" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 800, "y": 480, "wires": [ [ "e0493a19.3f6e58" ] ] }, { "id": "6eb6479d.959bb8", "type": "comment", "z": "158e314c.71084f", "name": "AJAX Server", "info": "", "x": 90, "y": 440, "wires": [] }, { "id": "41127064.c939c", "type": "http in", "z": "158e314c.71084f", "name": "", "url": "/treadmill/jquery", "method": "get", "swaggerDoc": "", "x": 100, "y": 600, "wires": [ [ "a1421f74.fc4a7" ] ] }, { "id": "a1421f74.fc4a7", "type": "file in", "z": "158e314c.71084f", "name": "Get Jquery File", "filename": "/home/pi/.node-red/jquery.min.js", "format": "utf8", "x": 310, "y": 600, "wires": [ [ "38e5d7d5.bc3cf8" ] ] }, { "id": "38e5d7d5.bc3cf8", "type": "http response", "z": "158e314c.71084f", "name": "", "x": 480, "y": 600, "wires": [] }, { "id": "f49a223b.d2f59", "type": "comment", "z": "158e314c.71084f", "name": "Get Local JQuery File", "info": "", "x": 120, "y": 560, "wires": [] }, { "id": "d1e193de.63e5b", "type": "comment", "z": "158e314c.71084f", "name": "Read Default Config", "info": "This area tried to read treadmill.cfg.\nIf it fails it skips the whole area and\ngoes to Set Globals, where defaults are set.\nIf it succeeded and contains a value for\nusername it tries to read the user's setting file.\nIf not the it skips the user file read.\nIf the user file is there and read then its\nvalues are used. Otherwise it does nothing\nand the values in treadmill.cfg are used.", "x": 220, "y": 200, "wires": [] }, { "id": "f5cec652.9e6618", "type": "function", "z": "158e314c.71084f", "name": "Stop", "func": "if (msg.payload == 'stop')\n {\n// node.warn(\"Stopping...\");\n clearInterval(context.global.timerId);\n global.set(\"stop\",1);\n// var program = global.get(\"programs\")[global.get(\"program\")];\n var data = [];\n data[0] = \"
Program Stopped
\";\n data[1] = context.global.createChart(global.get(\"program\"));\n data[2] = \"endchart\";\n data[3] = {\"time\":0,\"speed\":0,\"secsleft\":0,\"incline\":0};\n var payload = JSON.stringify(data);\n msg.payload = [{\"count\":1,\"button\":\"Stop\"}];\n return [{payload:payload},msg];\n\n }\n", "outputs": "2", "noerr": 0, "x": 760, "y": 1340, "wires": [ [ "327331de.6a3d2e" ], [ "a451150a.24f988" ] ] }, { "id": "4b2bf575.bda25c", "type": "websocket in", "z": "158e314c.71084f", "name": "", "server": "8620b00f.557be", "client": "", "x": 590, "y": 1340, "wires": [ [ "f5cec652.9e6618" ] ] }, { "id": "a451150a.24f988", "type": "delay", "z": "158e314c.71084f", "name": "Wait for scheduler to end", "pauseType": "delay", "timeout": "250", "timeoutUnits": "milliseconds", "rate": "1", "rateUnits": "second", "randomFirst": "1", "randomLast": "5", "randomUnits": "seconds", "drop": false, "x": 960, "y": 1360, "wires": [ [ "702c9bfb.bdcb74" ] ] }, { "id": "7c20aceb.4d1274", "type": "subflow:1314db79.10bc15", "z": "158e314c.71084f", "x": 1380, "y": 1420, "wires": [ [ "ddd7751c.fcf3a8" ] ] }, { "id": "96a4ae77.b42a", "type": "function", "z": "158e314c.71084f", "name": "Set Imperial Units", "func": "msg.payload = [{\"count\":1,\"button\":\"InclineDown\"}];\nreturn msg;", "outputs": 1, "noerr": 0, "x": 140, "y": 1080, "wires": [ [ "f44fe1b5.1e05a" ] ] }, { "id": "f44fe1b5.1e05a", "type": "subflow:1314db79.10bc15", "z": "158e314c.71084f", "x": 347, "y": 1081, "wires": [ [ "8d75fdf2.fccd7" ] ] }, { "id": "fe1c89f.840e278", "type": "comment", "z": "158e314c.71084f", "name": "Stop Treadmill", "info": "", "x": 700, "y": 1300, "wires": [] }, { "id": "bb5ef6c6.28bac8", "type": "function", "z": "158e314c.71084f", "name": "Initialize Speed/Incline", "func": "var speedBaselineSteps =(global.get(\"userminspeed\") - global.get(\"minspeed\")); \nvar inclineBaselineSteps = (global.get(\"userminincline\") - global.get(\"minincline\"))/5.0; \n//node.warn('speed: ' + global.get(\"userminspeed\") + ' ' + global.get(\"minspeed\"));\n//node.warn(' incline: ' + global.get(\"userminincline\") + ' ' + global.get(\"minincline\"));\nmsg.payload = [{\"count\":speedBaselineSteps,\"button\":\"SpeedUp\"},{\"count\":inclineBaselineSteps,\"button\":\"InclineUp\"}];\n//node.warn(msg.payload);\nreturn msg;", "outputs": 1, "noerr": 0, "x": 570, "y": 1420, "wires": [ [ "bdabed30.4085b" ] ] }, { "id": "bdabed30.4085b", "type": "subflow:1314db79.10bc15", "z": "158e314c.71084f", "x": 780, "y": 1420, "wires": [ [ "7a270187.c9df5" ] ] }, { "id": "75041a1d.3b4404", "type": "http in", "z": "158e314c.71084f", "name": "", "url": "/treadmill/chartloader", "method": "get", "swaggerDoc": "", "x": 700, "y": 600, "wires": [ [ "f007ddaa.c2bba" ] ] }, { "id": "f007ddaa.c2bba", "type": "file in", "z": "158e314c.71084f", "name": "Get Gauge JS File", "filename": "/home/pi/.node-red/loader.js", "format": "utf8", "x": 920, "y": 600, "wires": [ [ "83b8182d.770e88" ] ] }, { "id": "83b8182d.770e88", "type": "http response", "z": "158e314c.71084f", "name": "", "x": 1080, "y": 600, "wires": [] }, { "id": "9e6a09f2.1cbd58", "type": "comment", "z": "158e314c.71084f", "name": "Get Local Gauges File", "info": "", "x": 700, "y": 560, "wires": [] }, { "id": "499dae18.c9d07", "type": "comment", "z": "158e314c.71084f", "name": "Read User Config", "info": "", "x": 340, "y": 260, "wires": [] }, { "id": "9bc73be0.62ab58", "type": "function", "z": "158e314c.71084f", "name": "Pause", "func": "global.set(\"pause\",1);\nvar data = [];\n//data[0] = \"
Program Paused
\";\ndata[0] = null;\ndata[1] = null;\ndata[2] = 'pause';\ndata[3] = null;\nvar payload = JSON.stringify(data);\nmsg.payload = [{\"count\":1,\"button\":\"Pause\"}];\nreturn [{payload:payload},msg];", "outputs": "2", "noerr": 0, "x": 960, "y": 1500, "wires": [ [ "1b44da52.c02e96" ], [ "7c7739be.cb0988" ] ] }, { "id": "4b2b8a1a.60ec64", "type": "websocket in", "z": "158e314c.71084f", "name": "", "server": "8620b00f.557be", "client": "", "x": 140, "y": 1520, "wires": [ [ "5cebf762.568268" ] ] }, { "id": "5cebf762.568268", "type": "switch", "z": "158e314c.71084f", "name": "Pause or Resume?", "property": "payload", "propertyType": "msg", "rules": [ { "t": "eq", "v": "pause", "vt": "str" }, { "t": "eq", "v": "resume", "vt": "str" } ], "checkall": "true", "outputs": 2, "x": 380, "y": 1500, "wires": [ [ "bcb78594.272f18", "9bc73be0.62ab58" ], [ "62a7eee1.2651d" ] ] }, { "id": "62a7eee1.2651d", "type": "function", "z": "158e314c.71084f", "name": "Resume", "func": "clearInterval(flow.get('pauseTimer'));\nglobal.set(\"pause\",0);\nvar data = [];\ndata[0] = \"
Program Running
\";\ndata[1] = null;\ndata[2] = 'resume';\ndata[3] = null;\nvar payload = JSON.stringify(data);\nmsg.payload = [{\"count\":1,\"button\":\"Start\"}];\nreturn [{payload:payload},msg];", "outputs": "2", "noerr": 0, "x": 650, "y": 1640, "wires": [ [ "1b44da52.c02e96" ], [ "4124c3fc.ba021c", "7c7739be.cb0988" ] ] }, { "id": "bcb78594.272f18", "type": "function", "z": "158e314c.71084f", "name": "Start Pause Countdown", "func": "var wait = 240;\nfunction formatTime(time)\n {\n var mins = Math.floor(time/60); \n var secs = time % 60;\n if (secs < 10)\n secs = '0' + secs;\n return mins + ':' + secs;\n }\nvar data = [];\ndata[0] = \"
Resuming in \" + formatTime(wait) +\" minutes
\";\ndata[1] = null;\ndata[2] = null;\ndata[3] = null;\nvar payload = JSON.stringify(data);\nnode.send([null,{payload:payload}]);\n\nvar timerId = setInterval(docountdown,1000);\nflow.set('pauseTimer',timerId);\n\nfunction docountdown()\n {\n stop = global.get('stop');\n if (stop != 1)\n {\n data[0] = \"
Resuming in \" + formatTime(wait) +\" minutes
\";\n data[1] = null;\n data[2] = null;\n data[3] = null;\n payload = JSON.stringify(data);\n node.send([null,{payload:payload}]);\n }\n \n if (stop != 1 && wait == 3) // start the treadmill\n {\n node.send([msg,null]);\n }\n\n if (wait === 0 || stop == 1 || global.get(\"pause\") === 0)\n {\n clearInterval(timerId);\n// node.warn(\"Ending wait\");\n } \n \n wait--;\n }", "outputs": "2", "noerr": 0, "x": 660, "y": 1560, "wires": [ [ "62a7eee1.2651d" ], [ "1b44da52.c02e96" ] ] }, { "id": "7c7739be.cb0988", "type": "subflow:1314db79.10bc15", "z": "158e314c.71084f", "x": 1100, "y": 1700, "wires": [ [] ] }, { "id": "cda23fd3.a79b2", "type": "function", "z": "158e314c.71084f", "name": "Hide Pause", "func": "var data = [];\ndata[0] = null;\ndata[1] = null;\ndata[2] = 'hidepause';\ndata[3] = null;\nvar payload = JSON.stringify(data);\nreturn [msg,{payload:payload}];\n", "outputs": "2", "noerr": 0, "x": 1200, "y": 1420, "wires": [ [ "7c20aceb.4d1274" ], [ "1b44da52.c02e96" ] ] }, { "id": "ddd7751c.fcf3a8", "type": "function", "z": "158e314c.71084f", "name": "Show Pause", "func": "var data = [];\ndata[0] = null;\ndata[1] = null;\ndata[2] = 'showpause';\ndata[3] = null;\nmsg.payload = JSON.stringify(data);\nreturn msg;", "outputs": 1, "noerr": 0, "x": 1540, "y": 1420, "wires": [ [ "1b44da52.c02e96" ] ] }, { "id": "1b44da52.c02e96", "type": "websocket out", "z": "158e314c.71084f", "name": "", "server": "8620b00f.557be", "client": "", "x": 1340, "y": 1540, "wires": [] }, { "id": "4124c3fc.ba021c", "type": "function", "z": "158e314c.71084f", "name": "Hide Pause", "func": "var data = [];\ndata[0] = null;\ndata[1] = null;\ndata[2] = 'hidepause';\ndata[3] = null;\nmsg.payload = JSON.stringify(data);\nreturn msg;\n", "outputs": "1", "noerr": 0, "x": 900, "y": 1640, "wires": [ [ "b8a6399.7be6ec8", "1b44da52.c02e96" ] ] }, { "id": "a63e2905.1ad7d8", "type": "function", "z": "158e314c.71084f", "name": "Show Pause", "func": "var data = [];\ndata[0] = null;\ndata[1] = null;\ndata[2] = 'showpause';\ndata[3] = null;\nmsg.payload = JSON.stringify(data);\nreturn msg;", "outputs": 1, "noerr": 0, "x": 1260, "y": 1640, "wires": [ [ "1b44da52.c02e96" ] ] }, { "id": "b8a6399.7be6ec8", "type": "delay", "z": "158e314c.71084f", "name": "", "pauseType": "delay", "timeout": "4", "timeoutUnits": "seconds", "rate": "1", "rateUnits": "second", "randomFirst": "1", "randomLast": "5", "randomUnits": "seconds", "drop": false, "x": 1110, "y": 1640, "wires": [ [ "a63e2905.1ad7d8" ] ] }, { "id": "702c9bfb.bdcb74", "type": "subflow:1314db79.10bc15", "z": "158e314c.71084f", "x": 1220, "y": 1360, "wires": [ [] ] }, { "id": "d80e90f6.78aec", "type": "inject", "z": "158e314c.71084f", "name": "Start Active Pulse", "topic": "", "payload": "1", "payloadType": "num", "repeat": "2", "crontab": "", "once": true, "x": 130, "y": 1700, "wires": [ [ "9ae24a7.e3f5cb8" ] ] }, { "id": "9ae24a7.e3f5cb8", "type": "trigger", "z": "158e314c.71084f", "op1": "1", "op2": "0", "op1type": "str", "op2type": "str", "duration": "1", "extend": false, "units": "s", "reset": "", "name": "Flash", "x": 310, "y": 1700, "wires": [ [ "76ada39b.12fd2c" ] ] }, { "id": "76ada39b.12fd2c", "type": "rpi-gpio out", "z": "158e314c.71084f", "name": "Activity Flasher", "pin": "29", "set": true, "level": "0", "freq": "", "out": "out", "x": 480, "y": 1700, "wires": [] }, { "id": "1476cb6.bfff335", "type": "rpi-gpio in", "z": "158e314c.71084f", "name": "Shutdown switch", "pin": "18", "intype": "up", "debounce": "25", "read": false, "x": 140, "y": 1780, "wires": [ [ "ba346fdf.9d1bf" ] ] }, { "id": "ba346fdf.9d1bf", "type": "exec", "z": "158e314c.71084f", "command": "sudo shutdown -h now", "addpay": false, "append": "", "useSpawn": "true", "timer": "", "oldrc": false, "name": "Shutdown", "x": 340, "y": 1780, "wires": [ [], [], [] ] } ]