33# For more info visit https://www.vcloudinfo.com/click-here
44# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig
55# -------------------------------------------------------------------
6- # Dreame Vacuum Orchestration - Room queue, away/on-demand runs
7- # Weekday sweep, weekend mop, bathrooms last, notifications
6+ # Dreame Vacuum Orchestration - Continuous phased sweep/mop with away/on-demand
7+ # Phases: sweep main, sweep baths, mop main, mop baths; notifications + idle auto-start
88# -------------------------------------------------------------------
99# #####################################################################
1010
1111# # 1. Helpers
1212# #####################################################################
1313
1414input_boolean :
15- l10s_vacuum_weekday_cycle_active :
16- name : L10s Weekday Cleaning Active
17- icon : mdi:robot-vacuum
1815 l10s_vacuum_on_demand :
19- name : Dream Clean (On-Demand)
20- icon : mdi:rocket-launch
16+ name : Dreame Clean (On-Demand)
17+ icon : mdi:robot-vacuum
2118
22- input_datetime :
23- l10s_vacuum_last_weekday_cycle :
24- name : L10s Last Weekday Cleaning Cycle
25- has_date : true
26- has_time : true
19+ input_select :
20+ l10s_vacuum_phase :
21+ name : L10s Vacuum Phase
22+ options :
23+ - sweep_main
24+ - sweep_bath
25+ - mop_main
26+ - mop_bath
27+ initial : sweep_main
28+ icon : mdi:playlist-check
2729
2830input_text :
2931 l10s_vacuum_room_queue :
3032 name : L10s Vacuum Room Queue
33+ # Room order (id:name): 14 Kitchen, 12 Dining, 10 Living, 7 Master Bedroom, 15 Foyer, 9 Stacey Office,
34+ # 17 Formal Dining, 13 Hallway, 8 Justin Bedroom, 6 Paige Bedroom, 4 Master Bathroom, 2 Office, 1 Pool Bath, 3 Kids Bathroom.
3135 icon : mdi:format-list-bulleted
3236 max : 255
3337 l10s_vacuum_room_catalog :
3438 name : L10s Vacuum Room Catalog
35- # Room order (id:name): 14 Kitchen, 12 Dining, 10 Living, 7 Master Bedroom, 15 Foyer, 9 Stacey Office,
36- # 17 Formal Dining, 13 Hallway, 8 Justin Bedroom, 6 Paige Bedroom, 4 Master Bathroom, 2 Office, 1 Pool Bath, 3 Kids Bathroom.
37- initial : " 14,12,10,7,15,9,17,13,8,6,4,2,1,3"
39+ initial : " 6,7,8,9,10,12,13,14,15,17,2,4,1,3"
3840 icon : mdi:map
3941 max : 255
4042 l10s_vacuum_rooms_cleaned_today :
@@ -52,54 +54,39 @@ script:
5254 mode : single
5355 sequence :
5456 - variables :
55- # Weekday runs are sweeping (vacuum only), weekend runs are mopping
56- cleaning_mode : " {{ 'mopping' if now().weekday() in [5, 6] else 'sweeping' }}"
5757 catalog_raw : " {{ states('input_text.l10s_vacuum_room_catalog') | default('', true) | string | replace(' ', '') }}"
58- queue_raw : " {{ states('input_text.l10s_vacuum_room_queue') | default('', true) | string | replace(' ', '') }}"
59- last_reset_raw : " {{ states('input_datetime.l10s_vacuum_last_weekday_cycle') }}"
60- last_reset_date_str : >
61- {% set dt = as_datetime(last_reset_raw, default=None) %}
62- {{ dt.date().isoformat() if dt is not none else '' }}
6358 catalog_ints : " {{ catalog_raw | regex_findall('[0-9]+') | map('int') | select('gt', 0) | list }}"
64- queue_ints : " {{ queue_raw | regex_findall('[0-9]+') | map('int') | select('gt', 0) | list }}"
65- # Seed if queue is empty AND last reset was not today
66- can_seed_today : " {{ last_reset_date_str == '' or last_reset_date_str != now().date().isoformat() }}"
67- will_seed : >
68- {% set empty_queue = queue_ints | length == 0 %}
69- {% set on_demand = is_state('input_boolean.l10s_vacuum_on_demand', 'on') %}
70- {{ (empty_queue or (on_demand and queue_ints | length <= 1)) and catalog_ints | length > 0 and (can_seed_today or on_demand) }}
71- seeded_queue_list : " {{ catalog_ints if will_seed else queue_ints }}"
72- valid_queue_list : " {{ seeded_queue_list }}"
73- # Define bathroom IDs for mopping separation
7459 bath_ids : [1, 3, 4]
75- nonbath_list : " {{ valid_queue_list | reject('in', bath_ids) | list }}"
76- bath_list : " {{ valid_queue_list | select('in', bath_ids) | list }}"
77- # Prioritize non-bathrooms first, then bathrooms
78- segments_to_clean : >
79- {% if nonbath_list | length > 0 %}
80- {{ nonbath_list }}
81- {% elif bath_list | length > 0 %}
82- {{ bath_list }}
60+ main_ids : " {{ catalog_ints | reject('in', bath_ids) | list }}"
61+ phase_order : ['sweep_main', 'sweep_bath', 'mop_main', 'mop_bath']
62+ phase_state : " {{ states('input_select.l10s_vacuum_phase') }}"
63+ phase : " {{ phase_state if phase_state in phase_order else 'sweep_main' }}"
64+ cleaning_mode : " {{ 'mopping' if 'mop_' in phase else 'sweeping' }}"
65+ queue_raw : " {{ states('input_text.l10s_vacuum_room_queue') | default('', true) | string | replace(' ', '') }}"
66+ queue_ints : " {{ queue_raw | regex_findall('[0-9]+') | map('int') | select('gt', 0) | list }}"
67+ phase_segments : >
68+ {% if phase == 'sweep_main' %}
69+ {{ main_ids }}
70+ {% elif phase == 'sweep_bath' %}
71+ {{ bath_ids }}
72+ {% elif phase == 'mop_main' %}
73+ {{ main_ids }}
8374 {% else %}
84- []
75+ {{ bath_ids }}
8576 {% endif %}
77+ segments_to_clean : " {{ queue_ints if queue_ints | length > 0 else phase_segments }}"
8678
8779 # 1. Seed the queue if necessary
8880 - choose :
8981 - conditions :
9082 - condition : template
91- value_template : " {{ will_seed }}"
83+ value_template : " {{ queue_ints | length == 0 and phase_segments | length > 0 }}"
9284 sequence :
9385 - service : input_text.set_value
9486 target :
9587 entity_id : input_text.l10s_vacuum_room_queue
9688 data :
97- value : " {{ catalog_raw }}"
98- - service : input_datetime.set_datetime
99- target :
100- entity_id : input_datetime.l10s_vacuum_last_weekday_cycle
101- data :
102- datetime : " {{ now().strftime('%Y-%m-%d %H:%M:%S') }}"
89+ value : " {{ phase_segments | join(',') }}"
10390 default : []
10491
10592 # 2. Check if there is anything to clean and stop if not
@@ -122,9 +109,6 @@ script:
122109 entity_id : vacuum.l10s_vacuum
123110 data :
124111 fan_speed : Standard
125- - service : input_boolean.turn_on
126- target :
127- entity_id : input_boolean.l10s_vacuum_weekday_cycle_active
128112 - service : dreame_vacuum.vacuum_clean_segment
129113 target :
130114 entity_id : vacuum.l10s_vacuum
@@ -138,36 +122,30 @@ script:
138122
139123automation :
140124
141- - alias : ' Away Vacuum: Reset Queue (Mon/Sat) '
142- id : 93a6e7dc-9c32-4d53-9f7c-651cd60f4b84
125+ - alias : ' Vacuum: Reset Cleaned List at 5am '
126+ id : 18f7b6d3-c02c-4ec1-88b3-0c3b8b4c6f7b
143127 trigger :
144128 - platform : time
145- at : ' 08:55:00'
146- condition :
147- - condition : time
148- weekday :
149- - mon
150- - sat
129+ at : ' 05:00:00'
151130 action :
152- - service : input_text.set_value
153- target :
154- entity_id : input_text.l10s_vacuum_room_queue
155- data :
156- value : " {{ states('input_text.l10s_vacuum_room_catalog') }}"
157131 - service : input_text.set_value
158132 target :
159133 entity_id : input_text.l10s_vacuum_rooms_cleaned_today
160134 data :
161135 value : " "
162- - service : input_boolean.turn_off
163- target :
164- entity_id : input_boolean.l10s_vacuum_weekday_cycle_active
165- - service : input_datetime.set_datetime
166- target :
167- entity_id : input_datetime.l10s_vacuum_last_weekday_cycle
168- data :
169- datetime : " {{ now().strftime('%Y-%m-%d %H:%M:%S') }}"
170- - service : input_boolean.turn_off
136+
137+ - alias : ' Vacuum: Auto-Start if Idle 3 Days'
138+ id : c6b3f1e8-9a3f-4098-9b9e-1c7f2d6f1d11
139+ trigger :
140+ - platform : time
141+ at : ' 16:00:00'
142+ condition :
143+ - condition : template
144+ value_template : >
145+ {% set last = state_attr('script.l10s_vacuum_start_next_room','last_triggered') %}
146+ {{ last is none or (now() - last).days >= 3 }}
147+ action :
148+ - service : input_boolean.turn_on
171149 target :
172150 entity_id : input_boolean.l10s_vacuum_on_demand
173151
@@ -202,9 +180,6 @@ automation:
202180 entity_id : input_boolean.l10s_vacuum_on_demand
203181 to : ' off'
204182 condition :
205- - condition : state
206- entity_id : input_boolean.l10s_vacuum_weekday_cycle_active
207- state : ' on'
208183 - condition : template
209184 value_template : >
210185 {{ is_state('vacuum.l10s_vacuum', 'cleaning') or is_state('vacuum.l10s_vacuum', 'returning') or is_state('vacuum.l10s_vacuum', 'paused') }}
@@ -223,52 +198,47 @@ automation:
223198 - platform : state
224199 entity_id : sensor.l10s_vacuum_current_room
225200 for : ' 00:03:00'
226- - platform : state
227- entity_id : vacuum.l10s_vacuum
228- to : ' cleaning'
229- for : ' 00:03:00'
230201 variables :
231202 room_map : {14:'kitchen',12:'dining-room',10:'living room',7:'master-bedroom',15:'foyer',9:'stacey-office',17:'formal-dining',13:'hallway',8:'justin-bedroom',6:'paige-bedroom',4:'master-bathroom',2:'office',1:'pool-bath',3:'kids-bathroom'}
232- catalog_raw : " {{ states('input_text.l10s_vacuum_room_catalog') | default('', true) | string | replace(' ', '') }}"
233- catalog_ints : " {{ catalog_raw | regex_findall('[0-9]+') | map('int') | select('gt', 0) | list }}"
234203 queue_raw : " {{ states('input_text.l10s_vacuum_room_queue') | default('', true) | string | replace(' ', '') }}"
235- queue_ints : " {{ queue_raw | regex_findall('[0-9]+') | map('int') | select('gt', 0) | list | default([], true) }}"
236- working_queue : " {{ queue_ints if queue_ints | length > 0 else catalog_ints }}"
204+ queue_ints : " {{ queue_raw | regex_findall('[0-9]+') | map('int') | list | default([], true) }}"
237205 current_room_id : " {{ trigger.to_state.attributes.room_id | default(state_attr('sensor.l10s_vacuum_current_room', 'room_id'), true) | int(0) }}"
238- matched_room_id : " {{ current_room_id if current_room_id > 0 and current_room_id in (working_queue | default([], true)) else 0 }}"
239- remaining_rooms : " {{ working_queue | reject('equalto', matched_room_id) | list | join(',') }}"
240- remaining_value : >
241- {% set rem = remaining_rooms | string %}
242- {% if rem | length == 0 and working_queue | length > 1 %}
243- {{ working_queue | join(',') }}
244- {% else %}
245- {{ rem }}
246- {% endif %}
247- remaining_value_str : >
248- {% set rv = remaining_value %}
249- {% if rv is string %}
250- {{ rv }}
251- {% elif rv is iterable %}
252- {{ rv | map('string') | join(',') }}
253- {% else %}
254- {{ rv | string }}
255- {% endif %}
206+ matched_room_id : " {{ current_room_id if current_room_id > 0 and current_room_id in (queue_ints | default([], true)) else 0 }}"
207+ remaining_list : >
208+ {% set rem = [] %}
209+ {% set removed = namespace(done=false) %}
210+ {% for r in queue_ints %}
211+ {% if not removed.done and r == matched_room_id %}
212+ {% set removed.done = true %}
213+ {% else %}
214+ {% set rem = rem + [r] %}
215+ {% endif %}
216+ {% endfor %}
217+ {{ rem }}
218+ remaining_rooms : " {{ remaining_list | join(',') }}"
219+ remaining_count : " {{ remaining_list | length }}"
220+ phase_order : ['sweep_main', 'sweep_bath', 'mop_main', 'mop_bath']
221+ phase_state : " {{ states('input_select.l10s_vacuum_phase') }}"
222+ phase : " {{ phase_state if phase_state in phase_order else 'sweep_main' }}"
223+ phase_index : " {{ phase_order.index(phase) if phase in phase_order else 0 }}"
224+ has_next_phase : " {{ phase_index < (phase_order | length) - 1 }}"
225+ next_phase : " {{ phase_order[phase_index + 1] if has_next_phase else '' }}"
256226
257227 condition :
258- # Only run if there's actually a queue and a room was successfully matched to the start of the queue
259- - condition : template
260- value_template : " {{ working_queue | length > 0 }}"
261228 - condition : template
262- value_template : " {{ matched_room_id != 0 }}"
229+ value_template : " {{ queue_ints | length > 0 }}"
263230 - condition : template
264231 value_template : " {{ matched_room_id != 0 }}"
232+ - condition : state
233+ entity_id : vacuum.l10s_vacuum
234+ state : ' cleaning'
265235
266236 action :
267237 - service : input_text.set_value
268238 target :
269239 entity_id : input_text.l10s_vacuum_room_queue
270240 data :
271- value : " {{ remaining_value_str }}"
241+ value : " {{ remaining_rooms }}"
272242 - variables :
273243 cleaned_raw : " {{ states('input_text.l10s_vacuum_rooms_cleaned_today') | default('', true) | string }}"
274244 cleaned_parts : " {{ cleaned_raw | regex_findall('[^,]+') | map('trim') | reject('equalto','') | list }}"
@@ -280,7 +250,6 @@ automation:
280250 {% else %}
281251 {{ parts | join(', ') }}
282252 {% endif %}
283- remaining_count : " {{ remaining_value_str | regex_findall('[^,]+') | length if remaining_value_str | length > 0 else 0 }}"
284253 - service : input_text.set_value
285254 target :
286255 entity_id : input_text.l10s_vacuum_rooms_cleaned_today
@@ -299,46 +268,39 @@ automation:
299268 - choose :
300269 - conditions :
301270 - condition : template
302- value_template : " {{ remaining_rooms | length > 0 }}"
271+ value_template : " {{ remaining_count > 0 }}"
303272 sequence :
304273 - service : script.l10s_vacuum_start_next_room
305274 - conditions :
306275 - condition : template
307- value_template : " {{ remaining_rooms | length == 0 }}"
276+ value_template : " {{ remaining_count == 0 and has_next_phase }}"
308277 sequence :
309- - service : input_boolean.turn_off
278+ - service : input_select.select_option
310279 target :
311- entity_id : input_boolean.l10s_vacuum_weekday_cycle_active
312- - service : input_datetime.set_datetime
280+ entity_id : input_select.l10s_vacuum_phase
281+ data :
282+ option : " {{ next_phase }}"
283+ - service : input_text.set_value
313284 target :
314- entity_id : input_datetime.l10s_vacuum_last_weekday_cycle
285+ entity_id : input_text.l10s_vacuum_room_queue
315286 data :
316- datetime : " {{ now().strftime('%Y-%m-%d %H:%M:%S') }}"
317-
318- - alias : ' Away Vacuum: Cycle Complete'
319- id : 8fa7779a-957b-49a3-84e7-36ca93c2e0d2
320- trigger :
321- - platform : state
322- entity_id : sensor.l10s_vacuum_task_status
323- to : ' completed'
324- - platform : state
325- entity_id : vacuum.l10s_vacuum
326- to : ' docked'
327- for : 00:05:00
328- condition :
329- - condition : template
330- value_template : " {{ is_state('sensor.l10s_vacuum_task_status', 'completed') }}"
331- - condition : template
332- value_template : " {{ (states('input_text.l10s_vacuum_room_queue') | replace(' ', '')) | length == 0 }}"
333- action :
334- - service : input_boolean.turn_off
335- target :
336- entity_id : input_boolean.l10s_vacuum_weekday_cycle_active
337- - service : input_datetime.set_datetime
338- target :
339- entity_id : input_datetime.l10s_vacuum_last_weekday_cycle
340- data :
341- datetime : " {{ now().strftime('%Y-%m-%d %H:%M:%S') }}"
287+ value : " "
288+ - service : script.l10s_vacuum_start_next_room
289+ - conditions :
290+ - condition : template
291+ value_template : " {{ remaining_count == 0 and not has_next_phase }}"
292+ sequence :
293+ - service : input_select.select_option
294+ target :
295+ entity_id : input_select.l10s_vacuum_phase
296+ data :
297+ option : " sweep_main"
298+ - service : input_text.set_value
299+ target :
300+ entity_id : input_text.l10s_vacuum_room_queue
301+ data :
302+ value : " "
303+ - service : script.l10s_vacuum_start_next_room
342304
343305 - alias : ' Vacuum Sensor Cleaning Silencer'
344306 id : 6548de52-a4a4-4df2-9d66-9c2c15577a7f
0 commit comments