Work-Time-Tracker
Node-RED

Work-Time-Tracker

Track your work day and get reminders to take a break.
A flow by Frifan

Download flow

Flow Details

A 7.5 hour countdown that pauses every hour and switches to a 10 minute countdown to remind the user to take a break. At the end of the countdown the message "STOP WORK" is displayed in red.

[ { "id":"mqtt_btn", "type":"mqtt in", "z":"flow", "name":"AWTRIX Button", "topic":"YOUR_MQTT_PREFIX/btn", "qos":"0", "datatype":"json", "broker":"mqtt_broker" }, { "id":"handle_btn", "type":"function", "z":"flow", "name":"Handle Middle Button", "func":"// states: idle, work, break\nlet state = global.get('workState') || 'idle';\nif(msg.payload.button!=='middle') return null;\nswitch(state) {\n case 'idle':\n global.set('workState','work');\n return {topic:'work_start'};\n case 'work':\n global.set('workState','break');\n return {topic:'break_start'};\n case 'break':\n global.set('workState','work');\n return {topic:'break_resume'};\n}\nreturn null;","outputs":1,"noerr":0}, { "id":"inject_tick", "type":"inject", "z":"flow", "name":"Every second", "props":[{"p":"payload"}], "repeat":"1", "once":false }, { "id":"publish_work", "type":"function", "z":"flow", "name":"Work Timer Tick", "func":"let state=global.get('workState');\nif(state!=='work') return null;\nlet start=global.get('workStart')||Date.now();\nlet elapsed=(Date.now()-start)/1000; // seconds\nlet total=7.5*3600;\nlet rem=Math.max(0, total-elapsed)|0;\nlet pct=((elapsed/total)*100)|0;\n// hourly break trigger\nglobal.set('lastHourTrig', global.get('lastHourTrig')||0);\nif(rem%3600===0 && rem!==total && rem/3600!==global.get('lastHourTrig')){\n global.set('lastHourTrig', rem/3600);\n global.set('workState','paused_for_break');\n return {topic:'hour_break'};\n}\nmsg.payload=JSON.stringify({icon:global.get('timerIcon'),text:rem,progress:pct,progressC:'#f00',progressBC:'#000'});\nmsg.topic=`${global.get('mqttPrefix')}/${global.get('customTopic')}`;\nreturn msg;","outputs":1,"noerr":0}, { "id":"work_start", "type":"function", "z":"flow", "name":"On Work Start", "func":"global.set('workStart', Date.now());\nglobal.set('lastHourTrig',0);\nreturn null;","outputs":1 }, { "id":"hour_break", "type":"switch", "z":"flow", "name":"Hourly Break", "property":"topic", "rules":[{"t":"eq","v":"hour_break"}] }, { "id":"notify_break", "type":"mqtt out", "z":"flow", "name":"Show 1 hr Break", "topic":"${mqttPrefix}/${customTopic}", "qos":"0", "retain":false, "broker":"mqtt_broker", "x":750,"y":300 }, { "id":"start_break_timer", "type":"function", "z":"flow", "name":"Prepare Break", "func":"// pause work tick\nglobal.set('workState','break_wait');\nmsg.payload=JSON.stringify({icon:global.get('breakIcon'),text:'1 hr break'});\nreturn msg;","outputs":1 }, { "id":"break_start", "type":"switch", "z":"flow", "name":"On Break Start", "property":"topic", "rules":[{"t":"eq","v":"break_start"}] }, { "id":"break_timer", "type":"delay", "z":"flow", "name":"10 min Break Timer", "pauseType":"delay", "timeout":"10","timeoutUnits":"minutes" }, { "id":"break_finish", "type":"function", "z":"flow", "name":"Break Complete", "func":"// after break\nmsg.topic=`${global.get('mqttPrefix')}/${global.get('customTopic')}`;\nmsg.payload=JSON.stringify({icon:global.get('breakIcon'),text:0});\nglobal.set('workState','work');\nreturn msg;","outputs":1 }, { "id":"publish_break", "type":"function", "z":"flow", "name":"Break Tick", "func":"let state=global.get('workState');\nif(state!=='break') return null;\nlet start=global.get('breakStart')||Date.now();\nlet elapsed=(Date.now()-start)/1000;\nlet total=10*60;\nlet rem=Math.max(0,total-elapsed)|0;\nmsg.topic=`${global.get('mqttPrefix')}/${global.get('customTopic')}`;\nmsg.payload=JSON.stringify({icon:global.get('breakIcon'),text:rem});\nreturn msg;","outputs":1 }, { "id":"mqtt_out", "type":"mqtt out", "z":"flow", "name":"AWTRIX Display", "topic":"", "qos":"0", "retain":false, "broker":"mqtt_broker" } ]
-- Flow first published on May 25, 2025.