I have a bunch of classes that provide Spark.functions in their constructors. Up until now, I’ve been instantiating instances of these classes in setup() and throwing them in a std::deque that I’ve defined at the top of my .ino and it has been working as expected. Namely, all of those Spark.functions show up when I run particle list from the command line.
Now, I’d like to be able to use another Spark.function to dynamically add those items to the deque during runtime. I have a function all written up and it seems to be managing the objects correctly, but I’m no longer getting those Spark.functions for the objects getting put in the deque.
Do all Spark.functions need to be defined in setup() (i.e. I just need to suck it up and build a router function), or am I missing something that would make this work?
Related question: If it’s the latter, is there a way to remove Spark.functions as well? I would have thought they’d vanish when the object destructs, but I also expected these Spark.functions to register dynamically, so… ¯_(ツ)_/¯
Functions can be added to the firmware at any time, but it’s not clear to me how often the cloud will ask the device to describe itself so that the cloud is aware of new functions added (calling @Dave for enlightenment!)
There is presently no way to remove functions - the use cases envisaged aren’t dynamic.
As a workaround, I suggest creating a master function, like “dispatch” for which you can register named handlers. You’d call a specific handler by invoking the “dispatch” function using a specific syntax that separates the handler name from the argument, e.g. function-name:arg (split the function name at the first colon.) The dispatch function separates the name from the argument, finds the handler with the given name, and calls it with the argument. Those handlers could be stored in a STL container and added/removed as desired. You could also expose a string variable that lists all the available function handlers, and update the variable as functions are added/removed.
I hope that’s clear! Happy to elaborate where needed.
Good question! The cloud assumes you’ve setup all your functions and variables in the first 0-60 seconds of being connected. It’ll send a describe request to the device shortly after connecting, and if nothing is returned, it’ll try again about 60-90 seconds later in case something was blocking. After that, the list of functions and variables are cached for the rest of the session.
The cloud also now supports partial describe messages, so there is nothing stopping a device from sending an unsolicited describe update with the newer functions / variables. We could also do something like a cache-busting special event? So you could signal to the cloud that it should ask for an updated describe message next time it needs to call a function / variable. It’d be important not to overuse this though, since it’ll add some lag to whatever thing you’re calling, etc, etc.
Yeah, I’m expecting adding these class instances to be relatively infrequent (we’re representing equipment connected to the digital pins, if you’re wondering at this point). I expect 1-6 calls of this ‘add’ function at any given time then probably nothing more for quite some time as once the aforementioned equipment is in use we wouldn’t want to change what’s wired to the Photon.
How would we go about sending one of those unsolicited partial describe messages?
I think we’d need to patch the firmware to notice that the list of registered functions / variables has changed significantly, and send an updated describe at some point (maybe right away, etc). I’ll open a task for this on our firmware to help track it.