import bpy
from bpy.props import EnumProperty, FloatProperty, IntProperty
import math

class FanClearAnimationOperator(bpy.types.Operator):
    """Clear animation data of selected objects and reset values"""
    bl_idname = "object.clear_animation"
    bl_label = "Clear Animation"

    def execute(self, context):
        for obj in context.selected_objects:
            obj.animation_data_clear()
            obj.rotation_euler = (0, 0, 0)  # Reset rotation to zero
        return {'FINISHED'}

class FanAnimationOperator(bpy.types.Operator):
    """Animate the rotation of selected objects as if they are fans"""
    bl_idname = "object.fan_animation"
    bl_label = "Fan Animation"

    rotation_type: EnumProperty(
        name="Rotation Type",
        items=[
            ('CONSTANT', "Constant Speed", "Constant speed rotation"),
        ],
        default='CONSTANT'
    )

    def execute(self, context):
        rotation_x = math.radians(context.scene.fan_rotation_x)
        rotation_y = math.radians(context.scene.fan_rotation_y)
        rotation_z = math.radians(context.scene.fan_rotation_z)
        end_rotation_x = math.radians(context.scene.fan_end_rotation_x)
        end_rotation_y = math.radians(context.scene.fan_end_rotation_y)
        end_rotation_z = math.radians(context.scene.fan_end_rotation_z)
        start_frame_x = context.scene.fan_start_frame_x
        end_frame_x = context.scene.fan_end_frame_x
        start_frame_y = context.scene.fan_start_frame_y
        end_frame_y = context.scene.fan_end_frame_y
        start_frame_z = context.scene.fan_start_frame_z
        end_frame_z = context.scene.fan_end_frame_z
        wobble_amplitude = math.radians(context.scene.fan_wobble_amplitude)
        wobble_frequency = context.scene.fan_wobble_frequency

        for obj in context.selected_objects:
            obj.rotation_mode = 'XYZ'

            # Set initial rotation to zero at frame 1
            obj.rotation_euler = (0, 0, 0)
            obj.keyframe_insert(data_path="rotation_euler", index=0, frame=1)
            obj.keyframe_insert(data_path="rotation_euler", index=1, frame=1)
            obj.keyframe_insert(data_path="rotation_euler", index=2, frame=1)

            # Wobble function
            def apply_wobble(angle, frame, axis):
                wobble = wobble_amplitude * math.sin(wobble_frequency * frame)
                return angle + wobble if axis == 'X' else (angle + wobble if axis == 'Y' else angle + wobble)

            # Set keyframes for X rotation with wobble
            for frame in range(start_frame_x, end_frame_x + 1):
                current_rotation = rotation_x + (end_rotation_x - rotation_x) * ((frame - start_frame_x) / (end_frame_x - start_frame_x))
                obj.rotation_euler[0] = apply_wobble(current_rotation, frame, 'X')
                obj.keyframe_insert(data_path="rotation_euler", index=0, frame=frame)

            # Set keyframes for Y rotation with wobble
            for frame in range(start_frame_y, end_frame_y + 1):
                current_rotation = rotation_y + (end_rotation_y - rotation_y) * ((frame - start_frame_y) / (end_frame_y - start_frame_y))
                obj.rotation_euler[1] = apply_wobble(current_rotation, frame, 'Y')
                obj.keyframe_insert(data_path="rotation_euler", index=1, frame=frame)

            # Set keyframes for Z rotation with wobble
            for frame in range(start_frame_z, end_frame_z + 1):
                current_rotation = rotation_z + (end_rotation_z - rotation_z) * ((frame - start_frame_z) / (end_frame_z - start_frame_z))
                obj.rotation_euler[2] = apply_wobble(current_rotation, frame, 'Z')
                obj.keyframe_insert(data_path="rotation_euler", index=2, frame=frame)

        return {'FINISHED'}

class FanAnimationPanel(bpy.types.Panel):
    """Panel for Fan Animation"""
    bl_label = "Fan Animation"
    bl_idname = "OBJECT_PT_fan_animation"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Fan Animation'  # New category

    def draw(self, context):
        layout = self.layout

        # X Rotation Subpanel
        layout.label(text="X Rotation:")
        row = layout.row()
        row.prop(context.scene, "fan_rotation_x")
        row = layout.row()
        row.prop(context.scene, "fan_end_rotation_x", text="End Rotation")

        # Y Rotation Subpanel
        layout.label(text="Y Rotation:")
        row = layout.row()
        row.prop(context.scene, "fan_rotation_y")
        row = layout.row()
        row.prop(context.scene, "fan_end_rotation_y", text="End Rotation")

        # Z Rotation Subpanel
        layout.label(text="Z Rotation:")
        row = layout.row()
        row.prop(context.scene, "fan_rotation_z")
        row = layout.row()
        row.prop(context.scene, "fan_end_rotation_z", text="End Rotation")

        # Wobble Settings Subpanel
        layout.label(text="Wobble Settings:")
        row = layout.row()
        row.prop(context.scene, "fan_wobble_amplitude", text="Wobble Amplitude")
        row = layout.row()
        row.prop(context.scene, "fan_wobble_frequency", text="Wobble Frequency")

        # Animation Settings Subpanel
        layout.label(text="Animation Settings:")
        row = layout.row()
        row.prop(context.scene, "fan_start_frame_x", text="Start Frame X")
        row.prop(context.scene, "fan_end_frame_x", text="End Frame X")
        row = layout.row()
        row.prop(context.scene, "fan_start_frame_y", text="Start Frame Y")
        row.prop(context.scene, "fan_end_frame_y", text="End Frame Y")
        row = layout.row()
        row.prop(context.scene, "fan_start_frame_z", text="Start Frame Z")
        row.prop(context.scene, "fan_end_frame_z", text="End Frame Z")

        layout.operator("object.fan_animation", text="Animate Fans")
        layout.operator("object.clear_animation", text="Clear Animation Data")

def register():
    bpy.utils.register_class(FanAnimationOperator)
    bpy.utils.register_class(FanAnimationPanel)
    bpy.utils.register_class(FanClearAnimationOperator)
    bpy.types.Scene.fan_rotation_type = EnumProperty(
        name="Rotation Type",
        items=[
            ('CONSTANT', "Constant Speed", "Constant speed rotation"),
        ],
        default='CONSTANT'
    )
    bpy.types.Scene.fan_rotation_x = FloatProperty(name="Rotation X", default=0.0, min=-360.0, max=360.0)
    bpy.types.Scene.fan_rotation_y = FloatProperty(name="Rotation Y", default=0.0, min=-360.0, max=360.0)
    bpy.types.Scene.fan_rotation_z = FloatProperty(name="Rotation Z", default=0.0, min=-360.0, max=360.0)
    bpy.types.Scene.fan_end_rotation_x = FloatProperty(name="End Rotation X", default=0.0, min=-360.0, max=360.0)
    bpy.types.Scene.fan_end_rotation_y = FloatProperty(name="End Rotation Y", default=0.0, min=-360.0, max=360.0)
    bpy.types.Scene.fan_end_rotation_z = FloatProperty(name="End Rotation Z", default=0.0, min=-360.0, max=360.0)
    bpy.types.Scene.fan_start_frame_x = IntProperty(name="Start Frame X", default=1, min=1)
    bpy.types.Scene.fan_end_frame_x = IntProperty(name="End Frame X", default=250, min=1)
    bpy.types.Scene.fan_start_frame_y = IntProperty(name="Start Frame Y", default=1, min=1)
    bpy.types.Scene.fan_end_frame_y = IntProperty(name="End Frame Y", default=250, min=1)
    bpy.types.Scene.fan_start_frame_z = IntProperty(name="Start Frame Z", default=1, min=1)
    bpy.types.Scene.fan_end_frame_z = IntProperty(name="End Frame Z", default=250, min=1)
    bpy.types.Scene.fan_wobble_amplitude = FloatProperty(name="Wobble Amplitude", default=10.0, min=0.0, max=360.0)
    bpy.types.Scene.fan_wobble_frequency = FloatProperty(name="Wobble Frequency", default=1.0, min=0.0, max=10.0)

def unregister():
    bpy.utils.unregister_class(FanAnimationOperator)
    bpy.utils.unregister_class(FanAnimationPanel)
    bpy.utils.unregister_class(FanClearAnimationOperator)
    del bpy.types.Scene.fan_rotation_type
    del bpy.types.Scene.fan_rotation_x
    del bpy.types.Scene.fan_rotation_y
    del bpy.types.Scene.fan_rotation_z
    del bpy.types.Scene.fan_end_rotation_x
    del bpy.types.Scene.fan_end_rotation_y
    del bpy.types.Scene.fan_end_rotation_z
    del bpy.types.Scene.fan_start_frame_x
    del bpy.types.Scene.fan_end_frame_x
    del bpy.types.Scene.fan_start_frame_y
    del bpy.types.Scene.fan_end_frame_y
    del bpy.types.Scene.fan_start_frame_z
    del bpy.types.Scene.fan_end_frame_z
    del bpy.types.Scene.fan_wobble_amplitude
    del bpy.types.Scene.fan_wobble_frequency

if __name__ == "__main__":
    register()
I want to  Allow user to set the start and end frame of wobble effect