UPDATE: I added a new method to MacroConnectionListener virtual void macroLoadedFromValueTree(int macroIndex, float value){} which I call when a new value tree is loaded for the macros. My custom component calls setMacroControl on the sliderValueChanged callback, and updates the slider value on the macroLoadedFromValueTree callback.
To watch the parameter, I search for the first parameter for that macro index and set up a parameter watcher, converting the NormalisableRange to a linear 0 to 1 value in the callback.
Since parameters can change with every preset, I set that parameter watcher up at the same time macroLoadedFromValueTree is called making sure to dispatch to the MessageManager for any repaints.
It's not as convenient as a UIConnection class, but it works.