blueprint: name: Synchronize 2 Home Assistant todo list description: This blueprint for Home Assistant synchronizes 2 to-do lists. Originally designed to sync Google Keep lists with the Bring shopping list, its versatility allows syncing any list. Currently limited to syncing only active items, those marked as completed are removed from the lists source_url: https://gist.github.com/hectorzin/53f9811ff2d6a673af9ff3a9801df7af domain: automation input: google_list: name: List 1 description: Select your first list to synchronize selector: entity: domain: - todo multiple: false bring_list: name: List 2 description: Select your second list to synchronize selector: entity: domain: - todo multiple: false temp_list: name: Temp List description: Select the temporary list that is used as the basis of the synchronization selector: entity: domain: - todo multiple: false trigger: - platform: state entity_id: - !input google_list - platform: state entity_id: - !input bring_list condition: [] action: - variables: google_list: !input google_list bring_list: !input bring_list temp_list: !input temp_list - service: todo.get_items target: entity_id: '{{ google_list }}' data: status: needs_action response_variable: google_incompleted - service: todo.get_items target: entity_id: '{{ bring_list }}' data: status: needs_action response_variable: bring_incompleted - service: todo.get_items target: entity_id: '{{ temp_list }}' data: status: needs_action response_variable: temp_incompleted - variables: deleted_items: "{%- for temp_item in temp_incompleted[temp_list]['items'] -%}\n \ {% set ns = namespace(found=false) %}\n {%- for google_item in google_incompleted[google_list]['items'] -%}\n {%- if google_item.summary|capitalize == temp_item.summary|capitalize -%}\n {% set ns.found = true %}\n {%- endif -%}\n {%- endfor -%}\n \ {%- if not ns.found -%}\n {{ temp_item.summary }};\n {%- endif -%}\n{%- endfor -%}\n{%- for temp_item in temp_incompleted[temp_list]['items'] -%}\n \ {% set ns = namespace(found=false) %}\n {%- for bring_item in bring_incompleted[bring_list]['items'] -%}\n {%- if bring_item.summary|capitalize == temp_item.summary|capitalize -%}\n {% set ns.found = true %}\n {%- endif -%}\n {%- endfor -%}\n \ {%- if not ns.found -%}\n {{ temp_item.summary }};\n {%- endif -%}\n{%- endfor -%}\n" - variables: deleted_items: "{% for index in range(deleted_items.split(';')|length-1) -%}\n \ {%- set item = deleted_items.split(';')[index] -%}\n {%- for google_item in google_incompleted[google_list]['items'] -%}\n {%- if item|capitalize == google_item.summary|capitalize -%}\n {{ google_item.summary }};\n {%- endif -%}\n {%- endfor -%}\n{%- endfor -%}\n{% for index in range(deleted_items.split(';')|length-1) -%}\n {%- set item = deleted_items.split(';')[index] -%}\n {%- for bring_item in bring_incompleted[bring_list]['items'] -%}\n {%- if item|capitalize == bring_item.summary|capitalize -%}\n {{ bring_item.summary }};\n {%- endif -%}\n {%- endfor -%}\n{%- endfor -%}\n" - repeat: for_each: '{{ (deleted_items).split('';'') | list }}' sequence: - condition: template value_template: '{{ repeat.item != "" }}' - service: todo.update_item target: entity_id: - '{{ temp_list }}' data: item: '{{ repeat.item }}' status: completed - variables: delete_google: "{% set ns = namespace(found=\"\") %} {%- for google_item in\ngoogle_incompleted[google_list]['items'] -%}\n {%- if google_item.summary|capitalize == repeat.item|capitalize -%}\n \ {% set ns.found = google_item.summary %}\n {%- endif -%}\n{%- endfor -%}\n{%- if ns.found != \"\" -%}\n {{ ns.found }}\n{%- else -%}\n \n{%- endif -%}\n" - if: - condition: template value_template: '{{ delete_google != "" }}' then: - service: todo.remove_item target: entity_id: - '{{ google_list }}' data: item: '{{ delete_google }}' - variables: delete_bring: "{% set ns = namespace(found=\"\") %}\n{%- for bring_item in bring_incompleted[bring_list]['items'] -%}\n {%- if bring_item.summary|capitalize == repeat.item|capitalize -%}\n {% set ns.found = bring_item.summary %}\n {%- endif -%}\n{%- endfor -%}\n{%- if ns.found != \"\" -%}\n {{ ns.found }}\n{%- else -%}\n \n{%- endif -%}\n" - if: - condition: template value_template: '{{ delete_bring != "" }}' then: - service: todo.update_item target: entity_id: - '{{ bring_list }}' data: item: '{{ delete_bring }}' status: completed - service: todo.get_items target: entity_id: '{{ temp_list }}' data: status: needs_action response_variable: temp_incompleted - service: todo.get_items target: entity_id: '{{ google_list }}' data: status: needs_action response_variable: google_incompleted - service: todo.get_items target: entity_id: '{{ bring_list }}' data: status: needs_action response_variable: bring_incompleted - variables: items_to_buy_rep: "{%- for google_item in google_incompleted[google_list]['items'] -%}\n {% set ns = namespace(found=false) %}\n {%- for temp_item in temp_incompleted[temp_list]['items'] -%}\n {%- if google_item.summary|capitalize == temp_item.summary|capitalize -%}\n {% set ns.found = true %}\n {%- endif -%}\n {%- endfor -%}\n \ {%- if not ns.found -%}\n {{ google_item.summary|capitalize }};\n {%- endif -%}\n{%- endfor -%}\n{%- for bring_item in bring_incompleted[bring_list]['items'] -%}\n {% set ns = namespace(found=false) %}\n {%- for temp_item in temp_incompleted[temp_list]['items'] -%}\n {%- if bring_item.summary|capitalize == temp_item.summary|capitalize -%}\n {% set ns.found = true %}\n {%- endif -%}\n {%- endfor -%}\n \ {%- if not ns.found -%}\n {{ bring_item.summary|capitalize }};\n {%- endif -%}\n{%- endfor -%}\n" - variables: items_to_buy: "{% for index in range(items_to_buy_rep.split(';')|length-1) -%}\n \ {% set ns = namespace(found=false) %}\n {%- set item = items_to_buy_rep.split(';')[index] -%}\n {% for index2 in range(index+1,items_to_buy_rep.split(';')|length-1) -%}\n {%- set item2 = items_to_buy_rep.split(';')[index2] -%}\n {%- if item == item2 -%}\n {% set ns.found = true %}\n {%- endif -%}\n {%- endfor -%}\n {%- if not ns.found -%}\n {{ item }};\n {%- endif -%}\n{%- endfor -%}\n" - service: todo.get_items target: entity_id: '{{ temp_list }}' data: status: completed response_variable: temp_completed - variables: items_to_delete: "{% for index in range(items_to_buy.split(';')|length-1) -%}\n \ {% set ns = namespace(found=false) %}\n {%- set item = items_to_buy.split(';')[index] -%}\n {%- for temp_item in temp_completed[temp_list]['items'] -%}\n {%- if item|capitalize == temp_item.summary|capitalize -%}\n {{ temp_item.summary }};\n {%- endif -%}\n {%- endfor -%}\n{%- endfor -%}\n" - repeat: for_each: '{{ (items_to_delete).split('';'') | list }}' sequence: - condition: template value_template: '{{ repeat.item != "" }}' - service: todo.remove_item target: entity_id: '{{ temp_list }}' data: item: '{{ repeat.item }}' - repeat: for_each: '{{ (items_to_buy).split('';'') | list }}' sequence: - condition: template value_template: '{{ repeat.item != "" }}' - service: todo.add_item target: entity_id: '{{ temp_list }}' data: item: '{{ repeat.item }}' - service: todo.get_items target: entity_id: '{{ temp_list }}' data: status: needs_action response_variable: temp_incompleted - variables: items_to_bring: "{%- for temp_item in temp_incompleted[temp_list]['items'] -%}\n \ {% set ns = namespace(found=false) %}\n {%- for bring_item in bring_incompleted[bring_list]['items'] -%}\n {%- if bring_item.summary|capitalize == temp_item.summary|capitalize -%}\n {% set ns.found = true %}\n {%- endif -%}\n {%- endfor -%}\n \ {%- if not ns.found -%}\n {{ temp_item.summary|capitalize }};\n {%- endif -%}\n{%- endfor -%}\n" - service: todo.get_items target: entity_id: '{{ bring_list }}' data: status: completed response_variable: bring_completed - variables: items_to_delete: "{% for index in range(items_to_bring.split(';')|length-1) -%}\n \ {% set ns = namespace(found=false) %}\n {%- set item = items_to_bring.split(';')[index] -%}\n {%- for bring_item in bring_completed[bring_list]['items'] -%}\n {%- if item|capitalize == bring_item.summary|capitalize -%}\n {{ bring_item.summary }};\n {%- endif -%}\n {%- endfor -%}\n{%- endfor -%}\n" - repeat: for_each: '{{ (items_to_delete).split('';'') | list }}' sequence: - condition: template value_template: '{{ repeat.item != "" }}' - service: todo.remove_item target: entity_id: '{{ bring_list }}' data: item: '{{ repeat.item }}' - repeat: for_each: '{{ (items_to_bring).split('';'') | list }}' sequence: - condition: template value_template: '{{ repeat.item != "" }}' - service: todo.add_item target: entity_id: '{{ bring_list }}' data: item: '{{ repeat.item }}' - variables: items_delete_bring: "{%- for bring_item in bring_incompleted[bring_list]['items'] -%}\n {% set ns = namespace(found=false) %}\n {%- for temp_item in temp_incompleted[temp_list]['items'] -%}\n {%- if bring_item.summary|capitalize == temp_item.summary|capitalize -%}\n {% set ns.found = true %}\n {%- endif -%}\n {%- endfor -%}\n \ {%- if not ns.found -%}\n {{ bring_item.summary }};\n {%- endif -%}\n{%- endfor -%}\n" - repeat: for_each: '{{ (items_delete_bring).split('';'') | list }}' sequence: - condition: template value_template: '{{ repeat.item != "" }}' - service: todo.update_item target: entity_id: '{{ bring_list }}' data: item: '{{ repeat.item }}' status: completed - variables: items_to_google: "{%- for temp_item in temp_incompleted[temp_list]['items'] -%}\n \ {% set ns = namespace(found=false) %}\n {%- for google_item in google_incompleted[google_list]['items'] -%}\n {%- if google_item.summary|capitalize == temp_item.summary|capitalize -%}\n {% set ns.found = true %}\n {%- endif -%}\n {%- endfor -%}\n \ {%- if not ns.found -%}\n {{ temp_item.summary|capitalize }};\n {%- endif -%}\n{%- endfor -%}\n" - service: todo.get_items target: entity_id: '{{ google_list }}' data: status: completed response_variable: google_completed - variables: items_to_delete: "{% for index in range(items_to_google.split(';')|length-1) -%}\n \ {% set ns = namespace(found=false) %}\n {%- set item = items_to_google.split(';')[index] -%}\n {%- for google_item in google_completed[google_list]['items'] -%}\n {%- if item|capitalize == google_item.summary|capitalize -%}\n {{ google_item.summary }};\n {%- endif -%}\n {%- endfor -%}\n{%- endfor -%}\n" - repeat: for_each: '{{ (items_to_delete).split('';'') | list }}' sequence: - condition: template value_template: '{{ repeat.item != "" }}' - service: todo.remove_item target: entity_id: '{{ google_list }}' data: item: '{{ repeat.item }}' - repeat: for_each: '{{ (items_to_google).split('';'') | list }}' sequence: - condition: template value_template: '{{ repeat.item != "" }}' - service: todo.add_item target: entity_id: '{{ google_list }}' data: item: '{{ repeat.item }}' - variables: items_delete_google: "{%- for google_item in google_incompleted[google_list]['items'] -%}\n {% set ns = namespace(found=false) %}\n {%- for temp_item in temp_incompleted[temp_list]['items'] -%}\n {%- if google_item.summary|capitalize == temp_item.summary|capitalize -%}\n {% set ns.found = true %}\n {%- endif -%}\n {%- endfor -%}\n \ {%- if not ns.found -%}\n {{ google_item.summary }};\n {%- endif -%}\n{%- endfor -%}\n" - repeat: for_each: '{{ (items_delete_google).split('';'') | list }}' sequence: - condition: template value_template: '{{ repeat.item != "" }}' - service: todo.update_item target: entity_id: '{{ google_list }}' data: item: '{{ repeat.item }}' status: completed mode: single