How to create a script or action to clean specific room ECOVACS X2

got it working aswell.
somehow it always adds the room 0 to it (as first), do not know why and how i get rid of it…

sequence:
  - target:
      device_id: 5cb17e282c4437ce93d63d6f71aa6fa7
    data:
      command: spot_area
      params:
        rooms:
          - 1
          - 6
          - 2
          - 8
        cleanings: 1
    action: vacuum.send_command
mode: single
description: ""
alias: clean_main

I was having the same issue (always starting at room 0), and I think I’ve found the solution. Rather then formatting the rooms as a yaml list, just supply a comma separated list. Not sure why, but this works for me:

sequence:
  - target:
      device_id: 5cb17e282c4437ce93d63d6f71aa6fa7
    data:
      command: spot_area
      params:
        rooms: 1,6,2,8
        cleanings: 1
    action: vacuum.send_command
mode: single
description: ""
alias: clean_main

This is how I solved it using a script with two selectors:

alias: Start Room Cleaning
sequence:
  - data:
      option: >-
        {{ iif(is_state('input_select.deebot_x9_pro_omni_work_mode', 'Vacuum &
        Mop'), 'vacuum_mop', work_mode | lower) }}
    target:
      entity_id: select.deebot_x9_pro_omni_work_mode
    action: select.select_option
  - data:
      command: clean_V2
      params:
        act: start
        content:
          type: freeClean
          value: >
            {% set room_map = states.vacuum.deebot_x9_pro_omni.attributes.rooms
            %} {# Get user selected rooms (variable 'area' from fields) #} {%
            set selected_rooms = area %} {# Initialize a namespace to allow
            appending to the list inside the loop #} {% set ns =
            namespace(commands=[]) %}

            {% if room_map is defined and selected_rooms is defined %}
              
              {% for room_name in selected_rooms %}
                {# Convert user-friendly name (e.g., "Guest Bathroom") to map key (e.g., "guest_bathroom") #}
                {% set room_key = room_name | lower | replace(' ', '_') %}
                
                {% if room_key in room_map %}
                  {# Construct the full command part (e.g., "1,2") and append it to the list #}
                  {% set room_id = room_map[room_key] | string %}
                  {% set ns.commands = ns.commands + ["1," ~ room_id] %}
                {% else %}
                  {{ log("Room '" ~ room_name ~ "' not found in vacuum map.", level='warning') }}
                {% endif %}
                
              {% endfor %}
              
            {% endif %}

            {# FINAL OUTPUT: Join the list of full command strings using a
            SEMICOLON (;) #} {{ ns.commands | join(';') }}
    target:
      entity_id: vacuum.deebot_x9_pro_omni
    action: vacuum.send_command
mode: single
fields:
  work_mode:
    name: Work Mode
    required: true
    selector:
      select:
        options:
          - Vacuum
          - Vacuum & Mop
    default: Vacuum
    description: The Work Mode to Select
  area:
    selector:
      select:
        options:
          - Guest Bathroom
          - Corridor
          - Bathroom
          - Bedroom
          - Kids Room
          - Dining Room
          - Kitchen
          - Living Room
        multiple: true
    name: Area
    description: Select areas to clean
    required: true
description: Start room cleaning for one or more rooms
icon: mdi:robot-vacuum

This is the result how it looks in the UI:

action: vacuum.send_command
target:
  entity_id: vacuum.t30cgen2
data:
  command: clean_V2
  params:
    act: start
    content:
      type: freeClean
      value: "1,3"

according to my testing, “1,3” means map 1, room 3

It is very important to verify if your robot uses old API or new API

If it responds to command: clean_V2 then it should use new API