It depends on the capabilities of your HMI for accessing UDTs and AOI.
I usually do everything in AOIs if it is practical.
If I need to have different AOI definitions be accessed in the same way I will use a UDT to defien the common Parameters.
SO I might have UDT Type "FakeInterfaceBlah" as an InOut on AOI "Do1", and I would have it as a InOut for another AOI type called "Do2"
SO you have
UDT FakeInterfaceBlah
AOI Do1
AOI Do2
Then you might have
FakeInterfaceBlah BlahInst1 (as an instance)
FakeInterfaceBlah BlahInst2
FakeInterfaceBlah BlahInst3
FakeInterfaceBlah BlahInst4
Then
Do1 Do1Inst1 With BlahInst1 as an InOut
Do1 Do1Inst2 With BlahInst2 as an InOut
Do2 Do2Inst1 With BlahInst3 as an InOut
Do2 Do2Inst2 With BlahInst4 as an InOut
But where this really gets handy is if I define an array of FakeInterfaceBlah and do this
Do1 Do1Inst1 With BlahInst[0] as an InOut
Do1 Do1Inst2 With BlahInst[1] as an InOut
Do2 Do2Inst1 With BlahInst[2] as an InOut
Do2 Do2Inst2 With BlahInst[3] as an InOut
then I can loop through it in other places in my code.
For your pushbuttons if your HMI can access AOIs then just use AOIs
but if you have different types of pushbutton stations with different features what I describe about making fake interfaces with UDTs might be helpful.
for example all of them may have a start and stop button but maybe some of them have a Jog button, and others have say a "Pause" Button. Put the Start and Stop Button in a UDT. And then you would have 2 or more AOIs defined.
Or you could Do the same thing bug instead of using a UST you can have a Start and Stop AOI and put that AOI in side 2 different APIs that define the "Jog" and pause behavior.
All of this is poor man's
polymorphism.
I will stop my ramblings now. Time to put the kids to bed.