More types of triggers
Similar to the new expression variables page, I think that some new types of triggers should be added to create some specialisation of different event sources. Perhaps these could be solved by adding new events types, but I think that these are flows that warrant some different UI.
In this, I propose that the Triggers tab becomes a split menu (similar to surfaces), with a few pages:
- Automations (the default selection), what we currently have
- Midi/Input, initial solution for #1709
- Webhooks #3661?
Midi/Input
I have been thinking about this for a few days, so this is semi planned.
For now this is intended to be for midi, but perhaps could extend to gamepad input later on.
Perhaps the fader/jog/shuttle of existing surfaces should hook into this, as a better workflow until we can handle them in the grid.
This needs some more exploration for how it should behave, there might want to be a couple of types within in, to handle different midi flows (buttons vs faders/pots)
Each of these triggers should have an event source, which allows picking things and there should not be a condition block.
For the 'button' behaviour, there should be activate&deactivate actions, perhaps even the duration groups that we have on normal buttons. This probably wants to have the rotary events too.
For 'value' behaviour, it might be that there wants to be a single actions block, to be triggered whenever it changes. The value from the fader/whatever should be exposed as a $(this:value) variable
Webhooks
This is less thought through, it was prompted by #3661
Triggering things in companion is a common request. I personally am doing it for some custom input from an IR receiver.
Today it requires making a request to certain paths, to trigger button presses which is sub-optimal.
Instead, it would be good if the user could define a list of custom 'webhooks'.
In this, the user should be able to specify a path to use (which will be prefixed with /api/webhook/), the http verb.
We could paste relevant info about the request into some variables $(this:body), $(this:headers) and $(this:query), and let the user build perform actions based on this.
As a follow up, we could add more options to this:
- restrict the ip address of caller
- option to require http basic auth
- builtin hmac verification check. some webhooks (eg github) allow doing some signature checking with a shared secret, could be nice if we could handle the check for the user
Q) Maybe this should also include being able to setup custom OSC paths? Having something similar for that would be great to have, or should it be its own page?
But not like the trigger system currently, where quickly-arriving triggers are missed?
So... thinking "big picture", is there a way to gently start pushing towards inputs/triggers being modules? Just like regular companion modules, they have a framework, and devs can add their own code to handle any conceivable type of input device. Then all the mess of controllers that require base companion support can just be delegated to modules. How much cleaner this could be! (http/tcp/midi/ir protocol modules as well as streamdeck, loupdeck, t-bars, etc. all as input modules. Companion devs of course would build modules for the existing controllers, removing them from the companion base code. A robust API for controlers and feedback, like already exists in Satellite, but with a template to allow devs to code their own. Is there a fundamental reason to not move in this direction other than time? Or am I missing something?
But not like the trigger system currently, where quickly-arriving triggers are missed?
the 'flaw' in the current system is quickly changing variables are missed, not the trigger event being lost.
is there a way to gently start pushing towards inputs/triggers being modules?
there is a plan/pitch to make surfaces be plugins/modules #2041, which will happen its just a matter of when will I get around to doing it.
Its quite a bit of work to untangle some of this and to figure out how to design it so that the modules can be used both by companion and satellite.
I havent put any thought into trigger events coming from modules tbh. They probably could, but it wont solve most of the use case of the changes proposed here
Then all the mess of controllers that require base companion support can just be delegated to modules.
not unless we design it to allow for this. I am not yet convinced that we should make the http/tcp/whatever be plugins, largely because they use completely different internal apis to surfaces, and they change so rarely that im not sure it is worth the effort/overhead for both us and for users.
Using the OSC api as a sample, the last time it had a functional change (not some reformatting/refactoring or updating for internal api changes, is I think november 2023 when support for the larger grid size was added.
So is it worth having this as a plugin? I dont know, but I am leaning towards maybe not.
Emberplus recently had some changes. But that was new functionality that no other service uses, so it required messing around with companion internals to support it. Having a separate api in the middle would have made that be more work.
Maybe if we had this separation then others would be more willing to work on these apis, or maybe not.
If we're considering more types of triggers, I'd still like to see some sort of Event Bus style functionality where any module can just publish data to the bus (or potentially control surfaces or devices). Then the user would create a type of trigger to subscribe to a certain topic on the Event Bus.
Some of my modules, such as Twitch, and Voicemeeter, can take in data very rapidly as it gets sent by the app/service, rather than polling, similar to the way MIDI would work with a fader potentially sending a large number of values very rapidly. Some time it doesn't always make sense for this to be a Variable, with all the overhead involved on each update.
An example of this would be Twitch, if I wanted to give new subscriber data to Companion users so that they can use that in other modules for on-screen graphics, having a last_subscriber variable wont help if someone gifts 100 subs, as most would get missed. If on the other hand my module could put all 100 events onto an Event Bus, and the Companion user simply sets up a trigger to subscriber to that topic, has an option set so all events fire once, some sort of delay option so regardless of what module is putting on to the Event Bus the delay/buffer size is handled consistently.
When it comes to controllers as modules, same thing could be done, create a controller module that gets keypresses, or MIDI signals, or whatever input, formats that data and publishes it to the Event Bus. This'd create a consistent data structure for how controller modules get that data into Companion, and triggers can be set up to do things based on those events.
Agreed. Triggers from variables isn't efficient. I understand about protocols, I really would be happy if just the "Buttons" and "Surfaces" tab on the Settings could eventually be replaced by input/controller modules. That being said, if there is an event bus as Jeff suggests, that every input module writes to and every control module reads from, with a unifed format (maybe based on the Satellite protocol?) then protocols could also be supported. As far as getting some help, I would be happy to work on a MIDI input module, I'm sure Phillip wouldn't mind tackling the ember-plus...
Jumping in here, and only somewhat skimming what was talked about....
I'd like to see the ability to fire a trigger from a button. We have multiple buttons in various positions or pages that also fire another button. We do this so we only have to remember to update the one button. It'd be nice if rather than storing the actions in the button we could store them as a trigger, then fire the trigger via the buttons that need to access it. It'd also be nice to have a way to view what buttons reference another button or trigger before editing (or in general), to prevent accidental mistakes. Technically this could be done currently by using a custom variable that changes on pressed and released to fire a trigger, but it'd be nice to be able to tell the trigger to watch a specific button or a button to fire a specific trigger. Rather than making a ton of extra custom variables.