Fade commands are essentially, spam commands sent from webCoRE to your bulb.
In other words, with a 500ms fade, it will likely only be one (or maybe two) commands.
(IE: still abrupt)
I think 4 seconds may be a good place to start, but feel free to experiment.
Here is a simple piston you can import, which should test fading both up and down.
(just import, point it to a single bulb, press Test, and sit back for 13 seconds)

(I did not set the starting level, so the first time you press Test may react strangely)
You can play with the duration in this test piston, and once you find numbers that look good to you, then you can incorporate that logic into any piston.
For reference:
Here is the log for fading from 100 to 0 in four seconds:
setLevel([88], [delay: 500])
setLevel([75], [delay: 1000])
setLevel([63], [delay: 1500])
setLevel([50], [delay: 2000])
setLevel([38], [delay: 2500])
setLevel([25], [delay: 3000])
setLevel([13], [delay: 3500])
setLevel([0], [delay: 4000])
Still a bit choppy, but you get the idea…