ConfigUi for object creation

This is a legacy forum which is locked for new topics. New topics should be started in one of the other forums under Extending Indigo
Forum rules
This is a legacy forum which is locked for new topics. New topics should be started in one of the other forums under Extending Indigo
Perry The Cynic
Posts: 857
Joined: Mon Apr 07, 2008 9:46 pm

ConfigUi for object creation

Post by Perry The Cynic »

There's a bit of a problem with how validateWhateverConfigUi deals with object creation. The method gets passed a null id. This means that:

1. There's no identifier for the object-being-created that can be used to stash information gained during UI validation. For example, I may have resolved an address field and established communications with a network device, and I want to hand this connection off to the object - but I can't.

2. Indigo lets the user open multiple object dialogs (they're not modal). The user can hit "+" multiple time and alternate setting up different objects before clicking OK. If the objects are of the same type, validateWhateverConfigUi cannot distinguish them at all - they have the same type string and a null id. The custom-config dialogs are currently modal, which barely saves us, but if you ever want those dialogs to be non-modal, the current interface will fail.

Recommendations:

A. Generate the IOM identifier when you start creating an object and pass it to the validation method. Yes, I realize it's "not a real object yet." Still, the id gives us something to hang data on. If I can set pluginProps on it from the UI, that would be downright wonderful. :-)

B. In the endWhateverConfigUi methods, let us add keys to the values Dict and (if not userCancelled) pass those directly to the new object's pluginProps.

Ideally I'd like both. Obviously, if I'm missing the intended usage, just tell me. :-)

Thanks
-- perry
User avatar
jay (support)
Site Admin
Posts: 19232
Joined: Wed Mar 19, 2008 11:52 am
Location: Austin, Texas
Contact:

Re: ConfigUi for object creation

Post by jay (support) »

There are several distinct places where you can hook in to the dialog lifecycle. In your case, you can do something similar to what I do in the iTunes plugin: implement the getDeviceConfigUiValues method. That method is called every time a config UI dialog is opened. The default implementation in the base class just takes the incoming pluginProps dictionary and returns that and an empty dict for error messages. In my plugin, I determine if this is a new device or an existing device and if it's a new device I prime the returned valuesDict with a unique identifier. Note that anything added to the userDict must correspond to a field in the ConfigUI, so just create hidden fields to hold that data.

This information is then passed to all subsequent methods in the valuesDict. If your dialog needs some odd processing, your plugin can create unique identifiers if it's a new device that can be used throughout the life of the dialog and tracked by your plugin. In the final endDeviceConfigUi call you can perform any cleanup that's needed. Using this pattern would work even if the dialogs weren't modal. We don't believe many plugins are going to need this type of complex interaction so we don't believe it's a significant burden on those that do. If we're proven wrong, we'll modify it in the future.

The only slightly annoying thing about this process is the need for the hidden field in the ConfigUI XML. At some point in the future we'll remove the requirement for that, but it's of little trouble as is.

So, A isn't necessary because you can create whatever temporary identifier you need to manage the dialog process. Remember, anything in the valuesDict is automatically stored in device's pluginProps.

B isn't necessary because validateActionConfigUI is always called on a save, which is where you'd need to update the valuesDict.
Jay (Indigo Support)
Twitter | Facebook | LinkedIn
Perry The Cynic
Posts: 857
Joined: Mon Apr 07, 2008 9:46 pm

Re: ConfigUi for object creation

Post by Perry The Cynic »

[...]implement the getDeviceConfigUiValues method [...]
Excellent. I must have missed that in the documentation. :-)

Any reason why you're using len(valuesDict) == 0 rather than not devId? I.e. what is the canonical test for object creation vs. object change?
B isn't necessary because validateActionConfigUI is always called on a save, which is where you'd need to update the valuesDict.
Well... for devices, events, etc. it's really a two-step process. The xyzWhateverConfigUi calls talk about one particular click of the Edit XYZ Settings button. They're done when the modal details UI closes. If the user then clicks Cancel in the main device dialog, no callback will tell me that the settings just all reverted to something else (right?). So it sounds like a configuration tracker must register for change notifications to be fool-proof, yes?

Anyway, what we've got is good enough for the 99% case. Thanks.
-- perry
User avatar
jay (support)
Site Admin
Posts: 19232
Joined: Wed Mar 19, 2008 11:52 am
Location: Austin, Texas
Contact:

Re: ConfigUi for object creation

Post by jay (support) »

Perry The Cynic wrote:Any reason why you're using len(valuesDict) == 0 rather than not devId? I.e. what is the canonical test for object creation vs. object change?
Because when we did that plugin devId (most likely) wasn't being passed in (it's the first plugin we did so has some oddities perhaps because of that). Either will work, but testing devId is probably the best way.
Perry The Cynic wrote:If the user then clicks Cancel in the main device dialog, no callback will tell me that the settings just all reverted to something else (right?). So it sounds like a configuration tracker must register for change notifications to be fool-proof, yes?
Not sure what you mean by configuration tracker - and if by change notifications you mean implementing those methods then yes. If you have some process that's running while the dialog is up, then you'd catch it in the endWhateverConfigUI if it were still running and stop it. That expresses the absolute final notification that the configUI dialog is closing.
Jay (Indigo Support)
Twitter | Facebook | LinkedIn
Perry The Cynic
Posts: 857
Joined: Mon Apr 07, 2008 9:46 pm

Re: ConfigUi for object creation

Post by Perry The Cynic »

Not sure what you mean by configuration tracker - and if by change notifications you mean implementing those methods then yes. If you have some process that's running while the dialog is up, then you'd catch it in the endWhateverConfigUI if it were still running and stop it. That expresses the absolute final notification that the configUI dialog is closing.
For anything but the plugin itself, the ConfigUI dialog sequence is a subfunction of what the user actually considers a configuration dialog for a device, event, action, etc. For what's actually stored permanently, the Cancel/OK buttons on that dialog rule, and there's no Python feedback on those at all.

Configure a custom device. Enter ConfigUI, make changes, and click OK. Then click Cancel on the device dialog. According to the plugin's ConfigUI callbacks, everything is peachy and changes were made - but in fact nothing changed. (This means that you can't use ConfigUI to ensure validity of configuration either - if the initial config is invalid, the user can always get it back with that Cancel button.)

The ConfigUI system is designed to drive a dialog, not to track state. It does fine for dialog maintenance (with that hidden-field trick of yours). It cannot safely be used to track config changes; and if a plugin needs to be sure that it catches the config-reversal that comes with the outer Cancel button, it needs to register for the big, heavy change notifications - the ConfigUI system will not do. That's what I mean.

Cheers
-- perry
User avatar
matt (support)
Site Admin
Posts: 21542
Joined: Mon Jan 27, 2003 1:17 pm
Location: Texas
Contact:

Re: ConfigUi for object creation

Post by matt (support) »

Note, however, that is one of the purposes of the deviceStartComm() and deviceStopComm() hooks. They get called when: the database first loads, devices are enabled or disabled, devices are added, devices are deleted, and device properties change. The latter occurs when OKing out of the main Device dialog. So those are really the hooks that should be used for opening hardware or network communication.

I understand that may not exactly what you are looking for, but can you provide me a concrete example where it won't work to push some of your logic into the start/stopComm hooks? I guess my point is if you need "config reversal" notification from work done inside the validateUI hooks, then I think your validateUI hook is doing too much work and some of it should be moved to the start/stopComm hooks. But we'll entertain any concrete examples you have where that won't work...
Image
Perry The Cynic
Posts: 857
Joined: Mon Apr 07, 2008 9:46 pm

Re: ConfigUi for object creation

Post by Perry The Cynic »

Note, however, that is one of the purposes of the deviceStartComm() and deviceStopComm() hooks. They get called when: the database first loads, devices are enabled or disabled, devices are added, devices are deleted, and device properties change. The latter occurs when OKing out of the main Device dialog. So those are really the hooks that should be used for opening hardware or network communication.
This is a very clean story. I like it a lot. However, in reality...

Take a GC-100 for which the user asked to use device 2:2 as an IR emitter. I've got to find it, connect to it, and read its configuration to see if there is such a device and whether it's configured right. If I want to present pop-up menus for choices, I need to completely enumerate the device. At that point, we've done all of the heavy lifting and got a perfectly good new network/device configuration running. I just need to hand that over to the device object... if the user actually clicked that Ok button all the way through.

(Note that I can't just do this ConfigUI gig without looking at the existing device. Connecting to a GC-100 again resets its previous connection, so I must look for an existing device connection and use that for the ConfigUI work.)

So endDeviceConfigUi can take the new access object and stash it somewhere out of sight until the comm callback tells me that the change actually went through, at which point I can apply it to the device. But ConfigUI and device don't (always) share identifiers, so I need that hidden-field trick of yours to generate one. And I need to come up with some way to clean up that stashed access object if the user changed their mind and clicked the outer Cancel button, because there's no comms-didn't-change-after-all notification.

The cleanest solution, for now, is to spin up the device in ConfigUI, validate with it, then spin it down completely at endDeviceConfigUi no matter the outcome. And then spin it back up from scratch in the comms layer. (After making sure we've given it enough time to settle. GC-IRx seems to have undocumented "you're too fast for me" behavior, as does much cheap-ish hardware.)

The message I'm trying to get through to you is this: keeping the ConfigUI layer is separate and distinct from the device-lifecycle layer is neat and clean and good, but it's a bit impractical. ConfigUI needs to deal with device state (often creating tentatively-changed configuration data and device state), and needs the ability to "leave" Python data to be picked up by comm layer mutations, and some way to throw that left-over state out when the user hits the outer Cancel.

This isn't a show-stopper issue. We can get by. But it's painful and brittle, so I'm letting you know.

Cheers
-- perry
User avatar
matt (support)
Site Admin
Posts: 21542
Joined: Mon Jan 27, 2003 1:17 pm
Location: Texas
Contact:

Re: ConfigUi for object creation

Post by matt (support) »

Thanks the example, that helps.

But I still get the feeling that somehow trying to back-out changes if the user hits CANCEL, versus letting the connection flow-through to the object for OK isn't necessarily a great idea. It seems like it might be more efficient in some cases (especially with the GC's problem with fast reconnects), but even if we provided the hooks it would seem to be more complex and error prone. For example, what happens when the user edits a Device they happen to have disabled, but then hit OK in the main dialog? Sure you could handle all the cases like that, but you'd have to make sure you do.

The device is going to have to know how, no matter what, to build up the full connection inside startComm. So fully closing down the connection after the plugin UI closes seems like the safest approach, albeit not most optimized.

I think what I'm not grocking is how doing that is going to be more brittle. Slower for the GC, I get, but I don't understand how it is more complex or error prone.
Image
Perry The Cynic
Posts: 857
Joined: Mon Apr 07, 2008 9:46 pm

Re: ConfigUi for object creation

Post by Perry The Cynic »

I think what I'm not grocking is how doing that is going to be more brittle. Slower for the GC, I get, but I don't understand how it is more complex or error prone.
The complexity comes from the GC-100 being a one-connection-at-a-time device. ConfigUI can't just connect to whatever address you've got in the dict; it needs to see if it changed and use the existing device if it hasn't. If the device is active, you can't really do this - ConfigUI runs on its own separate thread, and it's pretty much impossible to guarantee no interference when you've got incoming device data while the ConfigUI is open. Arguably, there ought to be a way to take a device offline while ConfigUI is happening for it (with automatic return-to-service when the user outer-cancels)...

Meanwhile, I've mostly retreated, in practice, to ConfigUI that just says "Type in the values you want, and once you've okayed everything I'll let you know how it goes." I realize that's somewhat cowardly of me, but still...

I think I've beaten this issue into a bloody pulp by now, so I'll let it go. Thanks for all the answers and advice. This is pretty cool stuff, despite my constant carping. :-)

Cheers
-- perry
Locked

Return to “Extending Indigo with Plugins and Python”