Holding a PTZ ONVIF Button for Continuous Movement in Home Assistant

Hi everyone,

I’m trying to configure a system to control a PTZ ONVIF camera in Home Assistant with a hold feature on control buttons (pan, tilt, zoom). My goal is to:

Start the camera movement when the button is held down (e.g., to move the camera left).

Stop the movement as soon as the button is released.

I’ve already set up my ONVIF integration and can send PTZ commands using services like onvif.ptz. However, I haven’t found a solution to detect and handle a hold action and the corresponding release action in Lovelace.

Has anyone successfully configured a system for continuous movement based on holding a button for PTZ cameras in Home Assistant?

If you have examples of YAML configurations, scripts, or custom solutions (JavaScript, automations, etc.), I’d love to see them!

Thanks in advance for your help.

type: custom:bubble-card
card_type: select
entity: select.camera_4_ptz_preset
scrolling_effect: false
show_icon: false
force_icon: false
show_name: true
show_state: false
show_last_changed: false
show_attribute: false
icon: mdi:camera-control
sub_button:
  - name: left
    icon: mdi:arrow-left
    tap_action:
      action: call-service
      service: onvif.ptz
      data:
        distance: 0.15
        move_mode: ContinuousMove
        pan: LEFT
        speed: 1
      target:
        entity_id: camera.camera_jardin_profile000_mainstream
    entity: camera.camera_jardin_profile000_mainstream
  - entity: camera.camera_jardin_profile000_mainstream
    name: up
    icon: mdi:arrow-up
    tap_action:
      action: call-service
      service: onvif.ptz
      data:
        distance: 0.5
        move_mode: ContinuousMove
        tilt: UP
        speed: 1
      target:
        entity_id: camera.camera_jardin_profile000_mainstream
  - name: down
    entity: camera.camera_jardin_profile000_mainstream
    tap_action:
      action: call-service
      service: onvif.ptz
      data:
        distance: 0.5
        move_mode: ContinuousMove
        tilt: DOWN
        speed: 1
      target:
        entity_id: camera.camera_jardin_profile000_mainstream
    icon: mdi:arrow-down
  - entity: camera.camera_jardin_profile000_mainstream
    name: right
    icon: mdi:arrow-right
    tap_action:
      action: call-service
      service: onvif.ptz
      data:
        distance: 0.15
        move_mode: ContinuousMove
        pan: RIGHT
        speed: 1
      target:
        entity_id: camera.camera_jardin_profile000_mainstream
  - entity: camera.camera_jardin_profile000_mainstream
    name: zoom-in
    icon: mdi:magnify-plus
    tap_action:
      action: call-service
      service: onvif.ptz
      data:
        move_mode: ContinuousMove
        zoom: ZOOM_IN
        continuous_duration: 1
      target:
        entity_id: camera.camera_jardin_profile000_mainstream
  - entity: camera.camera_jardin_profile000_mainstream
    name: zoom-in
    icon: mdi:magnify-minus
    tap_action:
      action: call-service
      service: onvif.ptz
      data:
        move_mode: ContinuousMove
        zoom: ZOOM_OUT
        continuous_duration: 1
      target:
        entity_id: camera.camera_jardin_profile000_mainstream
name: Cam. 4
card_layout: normal
styles: |2-