Auto-refreshing chore / task list with todo and node-red

Thought I would share this in case it’s of use to others!

I wanted to use the todo entity to track recurring tasks and chores in my house, so I put this together.

  • This will create three todo lists - one for weekly tasks, one for fortnightly (bi-weekly) and one for monthly tasks.
  • Tasks will automatically be assigned a due date when you add them
  • Once ticked as completed, the task will be assigned a new due date - 1, 2 or 4 weeks after being ticked (depending on the list you have added it to)
  • 2 days before the task is due again, it will automatically be moved from the Completed section to the To-Do section

You will need to create three todo entities - todo.weekly, todo.fortnightly and todo.monthly. I would also recommend activating persistent context storage in node-red so that if HA restarts it maintains data.

[{"id":"949196be916a8bda","type":"tab","label":"Tasks","disabled":false,"info":"","env":[]},{"id":"f1d7a87b7aa9d635","type":"trigger-state","z":"949196be916a8bda","name":"change","server":"c4920a33.918dc8","version":4,"inputs":0,"outputs":2,"exposeAsEntityConfig":"","entityId":"todo.weekly","entityIdType":"exact","debugEnabled":false,"constraints":[],"customOutputs":[],"outputInitially":false,"stateType":"str","enableInput":false,"x":70,"y":200,"wires":[["f9d240ed3ca0a5d8"],[]]},{"id":"9577ec62b40b760c","type":"api-call-service","z":"949196be916a8bda","name":"assign due date","server":"c4920a33.918dc8","version":5,"debugenabled":false,"domain":"todo","service":"update_item","areaId":[],"deviceId":[],"entityId":[],"data":"{\"item\":\"{{payload.new_state.summary}}\",\"due_date\":\"{{due}}\",\"entity_id\":\"todo.weekly\"}","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1540,"y":200,"wires":[["2293bf6a8d604e38"]]},{"id":"c1c8591ba9b6d7d0","type":"moment","z":"949196be916a8bda","name":"get due date","topic":"","input":"","inputType":"date","inTz":"Europe/London","adjAmount":"7","adjType":"days","adjDir":"add","format":"YYYY-MM-DD","locale":"C","output":"due","outputType":"msg","outTz":"Europe/London","x":1370,"y":200,"wires":[["9577ec62b40b760c"]]},{"id":"7b409971bf7b4b05","type":"switch","z":"949196be916a8bda","name":"saved data?","property":"#:(store)::weekly","propertyType":"flow","rules":[{"t":"null"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":330,"y":200,"wires":[["0a639985d671edd7"],["e832f21643f711d2"]]},{"id":"0a639985d671edd7","type":"change","z":"949196be916a8bda","name":"save","rules":[{"t":"set","p":"#:(store)::weekly","pt":"flow","to":"payload.response[\"todo.weekly\"].items","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":160,"wires":[[]]},{"id":"f9d240ed3ca0a5d8","type":"ha-api","z":"949196be916a8bda","name":"","server":"c4920a33.918dc8","version":1,"debugenabled":false,"protocol":"websocket","method":"get","path":"","data":"{\t    \"type\": \"execute_script\",\t    \"sequence\": [\t        {\t            \"service\" : \"todo.get_items\",\t            \"target\" : {\t                \"entity_id\" : \"todo.weekly\"\t            },\t            \"data\" : {\t                \"status\": [\"needs_action\", \"completed\"]\t            },\t            \"response_variable\" : \"service_result\"\t        },\t        {\t            \"stop\" : \"done\",\t            \"response_variable\": \"service_result\"\t        }\t    ]\t}","dataType":"jsonata","responseType":"json","outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"results"}],"x":190,"y":200,"wires":[["7b409971bf7b4b05"]]},{"id":"e832f21643f711d2","type":"change","z":"949196be916a8bda","name":"load saved","rules":[{"t":"set","p":"weekly","pt":"msg","to":"#:(store)::weekly","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":510,"y":200,"wires":[["3eac164916690352"]]},{"id":"3eac164916690352","type":"function","z":"949196be916a8bda","name":"get changes","func":"function compareArrays(newArray, oldArray) {\n    let changes = [];\n\n    newArray.forEach(newItem => {\n        let oldItem = oldArray.find(item => item.uid === newItem.uid);\n        if (!oldItem) {\n            changes.push({\n                old_state: null,\n                new_state: newItem\n            });\n        } else if (JSON.stringify(oldItem) !== JSON.stringify(newItem)) {\n            changes.push({\n                old_state: oldItem,\n                new_state: newItem\n            });\n        }\n    });\n\n    return changes;\n}\n\nlet newArray = msg.payload.response[\"todo.weekly\"].items;\nlet oldArray = msg.weekly;\n\nmsg.changes = compareArrays(newArray, oldArray);\n\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":670,"y":200,"wires":[["a268c9b395f9204c","a31143d9fb577532"]]},{"id":"8ff07e77fd7a0bcd","type":"change","z":"949196be916a8bda","name":"save","rules":[{"t":"set","p":"#:(store)::weekly","pt":"flow","to":"payload.response[\"todo.weekly\"].items","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1810,"y":200,"wires":[[]]},{"id":"ae401f9c442c6ce0","type":"switch","z":"949196be916a8bda","name":"new item?","property":"payload.old_state","propertyType":"msg","rules":[{"t":"null"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":1010,"y":200,"wires":[["06efa2dedcf61ff3"],["7b42e91eda3f02c6"]]},{"id":"2293bf6a8d604e38","type":"ha-api","z":"949196be916a8bda","name":"","server":"c4920a33.918dc8","version":1,"debugenabled":false,"protocol":"websocket","method":"get","path":"","data":"{\t    \"type\": \"execute_script\",\t    \"sequence\": [\t        {\t            \"service\" : \"todo.get_items\",\t            \"target\" : {\t                \"entity_id\" : \"todo.weekly\"\t            },\t            \"data\" : {\t                \"status\": [\"needs_action\", \"completed\"]\t            },\t            \"response_variable\" : \"service_result\"\t        },\t        {\t            \"stop\" : \"done\",\t            \"response_variable\": \"service_result\"\t        }\t    ]\t}","dataType":"jsonata","responseType":"json","outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"results"}],"x":1690,"y":200,"wires":[["8ff07e77fd7a0bcd"]]},{"id":"7b42e91eda3f02c6","type":"switch","z":"949196be916a8bda","name":"changed status?","property":"payload.new_state.status","propertyType":"msg","rules":[{"t":"neq","v":"payload.old_state.status","vt":"msg"}],"checkall":"true","repair":false,"outputs":1,"x":1030,"y":260,"wires":[["e7cb869c2c1dc09b"]]},{"id":"e7cb869c2c1dc09b","type":"switch","z":"949196be916a8bda","name":"new status?","property":"payload.new_state.status","propertyType":"msg","rules":[{"t":"eq","v":"completed","vt":"str"},{"t":"eq","v":"needs_action","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":1210,"y":260,"wires":[["c1c8591ba9b6d7d0"],[]]},{"id":"a31143d9fb577532","type":"change","z":"949196be916a8bda","name":"save","rules":[{"t":"set","p":"#:(store)::weekly","pt":"flow","to":"payload.response[\"todo.weekly\"].items","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":810,"y":160,"wires":[[]]},{"id":"a268c9b395f9204c","type":"function","z":"949196be916a8bda","name":"split and send","func":"for (var i = 0; i < msg.changes.length; i++) {\n    var newMsg = {};\n    newMsg.payload = msg.changes[i];\n    node.send(newMsg);\n}\nreturn null;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":840,"y":200,"wires":[["ae401f9c442c6ce0"]]},{"id":"06efa2dedcf61ff3","type":"switch","z":"949196be916a8bda","name":"has date?","property":"payload.new_state.due","propertyType":"msg","rules":[{"t":"null"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":1200,"y":200,"wires":[["c1c8591ba9b6d7d0"],[]]},{"id":"e377512aa69ad554","type":"trigger-state","z":"949196be916a8bda","name":"0000","server":"c4920a33.918dc8","version":4,"inputs":0,"outputs":2,"exposeAsEntityConfig":"","entityId":"sensor.time","entityIdType":"exact","debugEnabled":false,"constraints":[{"targetType":"this_entity","targetValue":"","propertyType":"current_state","propertyValue":"new_state.state","comparatorType":"is","comparatorValueDatatype":"str","comparatorValue":"00:00"}],"customOutputs":[],"outputInitially":false,"stateType":"str","enableInput":false,"x":70,"y":800,"wires":[["67a71756332e252b"],[]]},{"id":"67a71756332e252b","type":"ha-api","z":"949196be916a8bda","name":"","server":"c4920a33.918dc8","version":1,"debugenabled":false,"protocol":"websocket","method":"get","path":"","data":"{\t    \"type\": \"execute_script\",\t    \"sequence\": [\t        {\t            \"service\" : \"todo.get_items\",\t            \"target\" : {\t                \"entity_id\" : [\"todo.weekly\", \"todo.fortnightly\", \"todo.monthly\"]\t            },\t            \"data\" : {\t                \"status\": \"completed\"\t            },\t            \"response_variable\" : \"service_result\"\t        },\t        {\t            \"stop\" : \"done\",\t            \"response_variable\": \"service_result\"\t        }\t    ]\t}","dataType":"jsonata","responseType":"json","outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"results"}],"x":190,"y":800,"wires":[["41b47164fdaf5d41"]]},{"id":"41b47164fdaf5d41","type":"function","z":"949196be916a8bda","name":"split and send","func":"var categories = [\"todo.weekly\", \"todo.fortnightly\", \"todo.monthly\"];\n\nfor (var c = 0; c < categories.length; c++) {\n    var category = categories[c];\n    for (var i = 0; i < msg.payload.response[category].items.length; i++) {\n        var newMsg = {};\n        newMsg.payload = msg.payload.response[category].items[i];\n        newMsg.list = category;\n        node.send(newMsg);\n    }\n}\n\nreturn null;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":340,"y":800,"wires":[["55526e2be9cf076d"]]},{"id":"55526e2be9cf076d","type":"moment","z":"949196be916a8bda","name":"time","topic":"","input":"","inputType":"date","inTz":"Europe/London","adjAmount":0,"adjType":"days","adjDir":"add","format":"YYYY-MM-DD","locale":"C","output":"time","outputType":"msg","outTz":"Europe/London","x":490,"y":800,"wires":[["8d33daa83cb05950"]]},{"id":"8d33daa83cb05950","type":"function","z":"949196be916a8bda","name":"get days left","func":"// Assuming date1 and date2 are in the format \"YYYY-MM-DD\"\nlet date1 = msg.time;\nlet date2 = msg.payload.due;\n\nlet d1 = new Date(date1);\nlet d2 = new Date(date2);\n\n// Get the difference in milliseconds\nlet differenceInMs = d2.getTime() - d1.getTime();\n\n// Convert the difference from milliseconds to days\nlet differenceInDays = differenceInMs / (1000 * 60 * 60 * 24);\n\nmsg.days_remaining = differenceInDays;\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":630,"y":800,"wires":[["bf53943f58171914"]]},{"id":"bf53943f58171914","type":"switch","z":"949196be916a8bda","name":"<2","property":"days_remaining","propertyType":"msg","rules":[{"t":"lt","v":"2","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":770,"y":800,"wires":[["d5100e1fe26838df"]]},{"id":"d5100e1fe26838df","type":"api-call-service","z":"949196be916a8bda","name":"assign due date","server":"c4920a33.918dc8","version":5,"debugenabled":false,"domain":"todo","service":"update_item","areaId":[],"deviceId":[],"entityId":[],"data":"{\"item\":\"{{payload.summary}}\",\"status\":\"needs_action\",\"entity_id\":\"{{list}}\"}","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":920,"y":800,"wires":[["50d3830d24d83e34"]]},{"id":"34e4f2cb551941c8","type":"change","z":"949196be916a8bda","name":"save","rules":[{"t":"set","p":"#:(store)::weekly","pt":"flow","to":"payload.response[\"todo.weekly\"].items","tot":"msg"},{"t":"set","p":"#:(store)::fortnightly","pt":"flow","to":"payload.response[\"todo.fortnightly\"].items","tot":"msg"},{"t":"set","p":"#:(store)::monthly","pt":"flow","to":"payload.response[\"todo.monthly\"].items","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1190,"y":800,"wires":[[]]},{"id":"50d3830d24d83e34","type":"ha-api","z":"949196be916a8bda","name":"","server":"c4920a33.918dc8","version":1,"debugenabled":false,"protocol":"websocket","method":"get","path":"","data":"{\t    \"type\": \"execute_script\",\t    \"sequence\": [\t        {\t            \"service\" : \"todo.get_items\",\t            \"target\" : {\t                 \"entity_id\" : [\"todo.weekly\", \"todo.fortnightly\", \"todo.monthly\"]\t            },\t            \"data\" : {\t                \"status\": [\"needs_action\", \"completed\"]\t            },\t            \"response_variable\" : \"service_result\"\t        },\t        {\t            \"stop\" : \"done\",\t            \"response_variable\": \"service_result\"\t        }\t    ]\t}","dataType":"jsonata","responseType":"json","outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"results"}],"x":1070,"y":800,"wires":[["34e4f2cb551941c8"]]},{"id":"9bc6dc3a0af429e4","type":"trigger-state","z":"949196be916a8bda","name":"change","server":"c4920a33.918dc8","version":4,"inputs":0,"outputs":2,"exposeAsEntityConfig":"","entityId":"todo.fortnightly","entityIdType":"exact","debugEnabled":false,"constraints":[],"customOutputs":[],"outputInitially":false,"stateType":"str","enableInput":false,"x":70,"y":380,"wires":[["3fa9ac8cd2ab773e"],[]]},{"id":"cfa0c7e4a10d21a1","type":"api-call-service","z":"949196be916a8bda","name":"assign due date","server":"c4920a33.918dc8","version":5,"debugenabled":false,"domain":"todo","service":"update_item","areaId":[],"deviceId":[],"entityId":[],"data":"{\"item\":\"{{payload.new_state.summary}}\",\"due_date\":\"{{due}}\",\"entity_id\":\"todo.fortnightly\"}","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1540,"y":380,"wires":[["d167835f64264ee1"]]},{"id":"684214a8ba5c7277","type":"moment","z":"949196be916a8bda","name":"get due date","topic":"","input":"","inputType":"date","inTz":"Europe/London","adjAmount":"14","adjType":"days","adjDir":"add","format":"YYYY-MM-DD","locale":"C","output":"due","outputType":"msg","outTz":"Europe/London","x":1370,"y":380,"wires":[["cfa0c7e4a10d21a1"]]},{"id":"687a5f2a13dc766a","type":"switch","z":"949196be916a8bda","name":"saved data?","property":"#:(store)::fortnightly","propertyType":"flow","rules":[{"t":"null"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":330,"y":380,"wires":[["230c2d8ff1975764"],["0ba21c1754e1bf77"]]},{"id":"230c2d8ff1975764","type":"change","z":"949196be916a8bda","name":"save","rules":[{"t":"set","p":"#:(store)::fortnightly","pt":"flow","to":"payload.response[\"todo.fortnightly\"].items","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":340,"wires":[[]]},{"id":"3fa9ac8cd2ab773e","type":"ha-api","z":"949196be916a8bda","name":"","server":"c4920a33.918dc8","version":1,"debugenabled":false,"protocol":"websocket","method":"get","path":"","data":"{\t    \"type\": \"execute_script\",\t    \"sequence\": [\t        {\t            \"service\" : \"todo.get_items\",\t            \"target\" : {\t                \"entity_id\" : \"todo.fortnightly\"\t            },\t            \"data\" : {\t                \"status\": [\"needs_action\", \"completed\"]\t            },\t            \"response_variable\" : \"service_result\"\t        },\t        {\t            \"stop\" : \"done\",\t            \"response_variable\": \"service_result\"\t        }\t    ]\t}","dataType":"jsonata","responseType":"json","outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"results"}],"x":190,"y":380,"wires":[["687a5f2a13dc766a"]]},{"id":"0ba21c1754e1bf77","type":"change","z":"949196be916a8bda","name":"load saved","rules":[{"t":"set","p":"fortnightly","pt":"msg","to":"#:(store)::fortnightly","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":510,"y":380,"wires":[["139dc8643de660c4"]]},{"id":"139dc8643de660c4","type":"function","z":"949196be916a8bda","name":"get changes","func":"function compareArrays(newArray, oldArray) {\n    let changes = [];\n\n    newArray.forEach(newItem => {\n        let oldItem = oldArray.find(item => item.uid === newItem.uid);\n        if (!oldItem) {\n            changes.push({\n                old_state: null,\n                new_state: newItem\n            });\n        } else if (JSON.stringify(oldItem) !== JSON.stringify(newItem)) {\n            changes.push({\n                old_state: oldItem,\n                new_state: newItem\n            });\n        }\n    });\n\n    return changes;\n}\n\nlet newArray = msg.payload.response[\"todo.fortnightly\"].items;\nlet oldArray = msg.fortnightly;\n\nmsg.changes = compareArrays(newArray, oldArray);\n\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":670,"y":380,"wires":[["25407011be4ec400","892fb8b0223ed26e"]]},{"id":"142fc9b9e5d5fc41","type":"change","z":"949196be916a8bda","name":"save","rules":[{"t":"set","p":"#:(store)::fortnightly","pt":"flow","to":"payload.response[\"todo.fortnightly\"].items","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1810,"y":380,"wires":[[]]},{"id":"2822a0f720a088eb","type":"switch","z":"949196be916a8bda","name":"new item?","property":"payload.old_state","propertyType":"msg","rules":[{"t":"null"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":1010,"y":380,"wires":[["8b3a545654b210fe"],["f972f778e8d287ac"]]},{"id":"d167835f64264ee1","type":"ha-api","z":"949196be916a8bda","name":"","server":"c4920a33.918dc8","version":1,"debugenabled":false,"protocol":"websocket","method":"get","path":"","data":"{\t    \"type\": \"execute_script\",\t    \"sequence\": [\t        {\t            \"service\" : \"todo.get_items\",\t            \"target\" : {\t                \"entity_id\" : \"todo.fortnightly\"\t            },\t            \"data\" : {\t                \"status\": [\"needs_action\", \"completed\"]\t            },\t            \"response_variable\" : \"service_result\"\t        },\t        {\t            \"stop\" : \"done\",\t            \"response_variable\": \"service_result\"\t        }\t    ]\t}","dataType":"jsonata","responseType":"json","outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"results"}],"x":1690,"y":380,"wires":[["142fc9b9e5d5fc41"]]},{"id":"f972f778e8d287ac","type":"switch","z":"949196be916a8bda","name":"changed status?","property":"payload.new_state.status","propertyType":"msg","rules":[{"t":"neq","v":"payload.old_state.status","vt":"msg"}],"checkall":"true","repair":false,"outputs":1,"x":1030,"y":440,"wires":[["47a4aa73a4c26221"]]},{"id":"47a4aa73a4c26221","type":"switch","z":"949196be916a8bda","name":"new status?","property":"payload.new_state.status","propertyType":"msg","rules":[{"t":"eq","v":"completed","vt":"str"},{"t":"eq","v":"needs_action","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":1210,"y":440,"wires":[["684214a8ba5c7277"],[]]},{"id":"892fb8b0223ed26e","type":"change","z":"949196be916a8bda","name":"save","rules":[{"t":"set","p":"#:(store)::fortnightly","pt":"flow","to":"payload.response[\"todo.fortnightly\"].items","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":810,"y":340,"wires":[[]]},{"id":"25407011be4ec400","type":"function","z":"949196be916a8bda","name":"split and send","func":"for (var i = 0; i < msg.changes.length; i++) {\n    var newMsg = {};\n    newMsg.payload = msg.changes[i];\n    node.send(newMsg);\n}\nreturn null;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":840,"y":380,"wires":[["2822a0f720a088eb"]]},{"id":"8b3a545654b210fe","type":"switch","z":"949196be916a8bda","name":"has date?","property":"payload.new_state.due","propertyType":"msg","rules":[{"t":"null"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":1200,"y":380,"wires":[["684214a8ba5c7277"],[]]},{"id":"58ea7c9a2490a150","type":"trigger-state","z":"949196be916a8bda","name":"change","server":"c4920a33.918dc8","version":4,"inputs":0,"outputs":2,"exposeAsEntityConfig":"","entityId":"todo.monthly","entityIdType":"exact","debugEnabled":false,"constraints":[],"customOutputs":[],"outputInitially":false,"stateType":"str","enableInput":false,"x":70,"y":560,"wires":[["f4e3efa850272fd4"],[]]},{"id":"bbad9da5a9e9e70d","type":"api-call-service","z":"949196be916a8bda","name":"assign due date","server":"c4920a33.918dc8","version":5,"debugenabled":false,"domain":"todo","service":"update_item","areaId":[],"deviceId":[],"entityId":[],"data":"{\"item\":\"{{payload.new_state.summary}}\",\"due_date\":\"{{due}}\",\"entity_id\":\"todo.monthly\"}","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1540,"y":560,"wires":[["9ec56908da9a3c50"]]},{"id":"be1116acd25b0a3b","type":"moment","z":"949196be916a8bda","name":"get due date","topic":"","input":"","inputType":"date","inTz":"Europe/London","adjAmount":"28","adjType":"days","adjDir":"add","format":"YYYY-MM-DD","locale":"C","output":"due","outputType":"msg","outTz":"Europe/London","x":1370,"y":560,"wires":[["bbad9da5a9e9e70d"]]},{"id":"4fae201ec764c9b3","type":"switch","z":"949196be916a8bda","name":"saved data?","property":"#:(store)::monthly","propertyType":"flow","rules":[{"t":"null"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":330,"y":560,"wires":[["204bd3d0570999a5"],["812965e2ebf9f24a"]]},{"id":"204bd3d0570999a5","type":"change","z":"949196be916a8bda","name":"save","rules":[{"t":"set","p":"#:(store)::monthly","pt":"flow","to":"payload.response[\"todo.monthly\"].items","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":520,"wires":[[]]},{"id":"f4e3efa850272fd4","type":"ha-api","z":"949196be916a8bda","name":"","server":"c4920a33.918dc8","version":1,"debugenabled":false,"protocol":"websocket","method":"get","path":"","data":"{\t    \"type\": \"execute_script\",\t    \"sequence\": [\t        {\t            \"service\" : \"todo.get_items\",\t            \"target\" : {\t                \"entity_id\" : \"todo.monthly\"\t            },\t            \"data\" : {\t                \"status\": [\"needs_action\", \"completed\"]\t            },\t            \"response_variable\" : \"service_result\"\t        },\t        {\t            \"stop\" : \"done\",\t            \"response_variable\": \"service_result\"\t        }\t    ]\t}","dataType":"jsonata","responseType":"json","outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"results"}],"x":190,"y":560,"wires":[["4fae201ec764c9b3"]]},{"id":"812965e2ebf9f24a","type":"change","z":"949196be916a8bda","name":"load saved","rules":[{"t":"set","p":"monthly","pt":"msg","to":"#:(store)::monthly","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":510,"y":560,"wires":[["1fe8429b9e714168"]]},{"id":"1fe8429b9e714168","type":"function","z":"949196be916a8bda","name":"get changes","func":"function compareArrays(newArray, oldArray) {\n    let changes = [];\n\n    newArray.forEach(newItem => {\n        let oldItem = oldArray.find(item => item.uid === newItem.uid);\n        if (!oldItem) {\n            changes.push({\n                old_state: null,\n                new_state: newItem\n            });\n        } else if (JSON.stringify(oldItem) !== JSON.stringify(newItem)) {\n            changes.push({\n                old_state: oldItem,\n                new_state: newItem\n            });\n        }\n    });\n\n    return changes;\n}\n\nlet newArray = msg.payload.response[\"todo.monthly\"].items;\nlet oldArray = msg.monthly;\n\nmsg.changes = compareArrays(newArray, oldArray);\n\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":670,"y":560,"wires":[["8d05c53cd765e2db","e0c093aaf5a1409c"]]},{"id":"a028ad6e7d59df27","type":"change","z":"949196be916a8bda","name":"save","rules":[{"t":"set","p":"#:(store)::monthly","pt":"flow","to":"payload.response[\"todo.monthly\"].items","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1810,"y":560,"wires":[[]]},{"id":"f56417cd1eaf274c","type":"switch","z":"949196be916a8bda","name":"new item?","property":"payload.old_state","propertyType":"msg","rules":[{"t":"null"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":1010,"y":560,"wires":[["2008a9873cfd3f28"],["def35e8808b5960b"]]},{"id":"9ec56908da9a3c50","type":"ha-api","z":"949196be916a8bda","name":"","server":"c4920a33.918dc8","version":1,"debugenabled":false,"protocol":"websocket","method":"get","path":"","data":"{\t    \"type\": \"execute_script\",\t    \"sequence\": [\t        {\t            \"service\" : \"todo.get_items\",\t            \"target\" : {\t                \"entity_id\" : \"todo.monthly\"\t            },\t            \"data\" : {\t                \"status\": [\"needs_action\", \"completed\"]\t            },\t            \"response_variable\" : \"service_result\"\t        },\t        {\t            \"stop\" : \"done\",\t            \"response_variable\": \"service_result\"\t        }\t    ]\t}","dataType":"jsonata","responseType":"json","outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"results"}],"x":1690,"y":560,"wires":[["a028ad6e7d59df27"]]},{"id":"def35e8808b5960b","type":"switch","z":"949196be916a8bda","name":"changed status?","property":"payload.new_state.status","propertyType":"msg","rules":[{"t":"neq","v":"payload.old_state.status","vt":"msg"}],"checkall":"true","repair":false,"outputs":1,"x":1030,"y":620,"wires":[["d8f8755094d84e90"]]},{"id":"d8f8755094d84e90","type":"switch","z":"949196be916a8bda","name":"new status?","property":"payload.new_state.status","propertyType":"msg","rules":[{"t":"eq","v":"completed","vt":"str"},{"t":"eq","v":"needs_action","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":1210,"y":620,"wires":[["be1116acd25b0a3b"],[]]},{"id":"e0c093aaf5a1409c","type":"change","z":"949196be916a8bda","name":"save","rules":[{"t":"set","p":"#:(store)::monthly","pt":"flow","to":"payload.response[\"todo.monthly\"].items","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":810,"y":520,"wires":[[]]},{"id":"8d05c53cd765e2db","type":"function","z":"949196be916a8bda","name":"split and send","func":"for (var i = 0; i < msg.changes.length; i++) {\n    var newMsg = {};\n    newMsg.payload = msg.changes[i];\n    node.send(newMsg);\n}\nreturn null;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":840,"y":560,"wires":[["f56417cd1eaf274c"]]},{"id":"2008a9873cfd3f28","type":"switch","z":"949196be916a8bda","name":"has date?","property":"payload.new_state.due","propertyType":"msg","rules":[{"t":"null"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":1200,"y":560,"wires":[["be1116acd25b0a3b"],[]]},{"id":"885f39cbe3d99b7f","type":"comment","z":"949196be916a8bda","name":"weekly","info":"","x":70,"y":160,"wires":[]},{"id":"8b4f1201705c9669","type":"comment","z":"949196be916a8bda","name":"fortnightly","info":"","x":80,"y":340,"wires":[]},{"id":"521f1ec42832df3e","type":"comment","z":"949196be916a8bda","name":"monthly","info":"","x":70,"y":520,"wires":[]},{"id":"5361f89104825bce","type":"comment","z":"949196be916a8bda","name":"repopulate when due","info":"","x":120,"y":760,"wires":[]},{"id":"c4920a33.918dc8","type":"server","name":"Home Assistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30,"areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true}]