Understanding Signals
The Captivate backend exposes a variety of “signals” that you can connect to for getting instant updates from the Captivate backend.
Signals
To connect to one of these signals, call the connect method (i.e. scheduler.[SIGNALNAME].connect
) on the desired signal and provide a callback that will handle the signal data. Signal data will be different for each signal and is specified in the list below.
You can later stop listening to signal data by calling the disconnect
method with the same callback object.
Note: If you call the connect method with an anonymous function, you will never be able to disconnect because that function was given anonymously. If you will need to call disconnect, remember to keep a reference to your callback function.
The most useful of all the signals is onNotify
since it allows you to receive updates whenever a title’s play status or data variables change. Use this in combination with a subscribe
command according to the example below.
onNotify
- Sends JSON-encoded notification data according to a previoussubscribe
command as well as all command messages passing through the command bus.newCommandXML
- Sends an XML document with detailed information on changes made in the Captivate UI.messageIn
- When another controller calls themessageOut
method, the connected function will be called with three arguments:from
,to
,data
wheredata
is a JSON-encoded JavaScript object.redirected
- Informs when the HTML page in the Data Controller is redirected (rarely used).serverPortChanged
- When server ports were changed (rarely used).settingsChanged
- The connected function will be called with theinputName
as the first argument and should then request the latest settings from the server.variablesChanged
- The function you connect will be called with theinputName
as the first argument (or"all"
if an input name was not specified in the update command) and a map of changed variables as the second argument.This function doesn’t work entirely as expected. It was originally designed to keep controller UI in sync with the true state of the Captivate system, but it only reports controller variable changes made through API calls. Remember that editing a variable from the Live Data panel or through using the Cache List directly affects the graphic variable and therefore doesn’t trigger this callback. If you want to keep track of graphic variable updates, you should
subscribe
to thedata
event.
Example 1:
/**
* Normally, only the values that actually changed are contained in the callback,
* however when first connecting the server, all variables' values will be sent over.
* This is to make sure the controls are populated with initial default values and
* ensures the values aren't lost when reloading the page.
*
* Because there is a single server for all HTML inputs, this callback will be fired for
* *any* variable change and will have data that might not be relevant to this controller,
* so be sure to filter on the input name.
*/
scheduler.variablesChanged.connect((inputName, variables) => {
if (inputName == INPUT_NAME) {
console.log('variables changed', variables);
}
});
Example 2:
const my_name = 'My Subscriber';
const my_input = ServiceHandler.inputName;
/**
* The `subscribe` command tells Captivate to register a new "subscription" or modify an existing one.
*
* Internally, subscriptions are identified by the value sent as the "sender" and many data controllers
* leave this value blank to share the existing notification sender in the system.
*
* However, if you want to control what your data controller sees, it's helpful to specify your own sender
* and customize the events, titles, and/or inputs that send notifications.
*
* If a subsequent "subscribe" command is sent with the same sender name, any new parameters will be
* appended to the existing ones.
*
* If you register a subscription with a sender, it's good practice to make sure you later send an
* unsubscribe command with that same sender name and event list so it gets cleaned up inside Captivate
*
* The following command will create a new sender identified by `my_name` and will ask for all
* play and data notifications that relate to the specified input.
*/
scheduler.scheduleCommand('subscribe', { input: my_input, events: 'play,data', sender: my_name }, {});
// setup the callback
const handler = (messageText) => {
console.info('Notification Received:', messageText);
// Convert the payload string into a JavaScript object.
let data = JSON.parse(messageText);
// The WebSocket API sends all notifications to all controllers,
// so ignore the ones we don't want.
if (data.sender != my_name) return;
// log the data
console.log(data);
// now that we have our data, we can also stop listening
scheduler.onNotify.disconnect(handler);
// clean up after ourselves
scheduler.scheduleCommand('unsubscribe', { sender: my_name, events: 'play,data' }, {});
};
// connect the callback
scheduler.onNotify.connect(handler);
A Note About Notification Senders
The sender name you specify in the subscribe command creates a subscription object in the Captivate backend. You can modify it by adding or removing event subscriptions as you wish. This can also be useful in your message handling code to make sure you are only paying attention to messages that come from the sender you are interested in. However, the tight coupling of sender and notification messages only happens with the External API connection methods.
The WebSocket API, for legacy reasons, currently sends all notification messages to all WebSocket clients regardless of what sender they have subscribed to and it does this for every inter-process message whether the target input can be found or not. Since the other API connection methods are more selective with their message passing, the WebSocket API might move in that direction in future releases. Therefore, for your controllers, it’s good practice to specify a sender name for all subscribe operations, and to have your notification handler discard all messages that don’t come from that sender.
Last updated