Exhibitera
Developing with Exhibitera
While Exhibitera Apps enables many kinds of interactives, you can also develop your own apps that integrate with Hub.
Building a browser-based app
The apps in Exhibitera Apps are built using JavaScript. This approach ensures maximum flexibility, while also offloading many performance and security concerns to the rendering engine. It also makes developing your own app surprisingly easy!
Exhibitera Apps provides a JavaScript module, exhibitera_app_common.js
, that enables easy connection with Exhibitera. In just a few lines of code, you can have an app up and running! Here is the complete code to create a blank Exhibitera app (the JavaScript file, at least):
import * as exCommon from 'exhibitera_app_common.js'
function loadDefinition (definition) {
// A function to configure your app's content
// based on the provided configuration.
...
}
function parseUpdate (update) {
// A function to respond to commands from
// Exhibitera Hub.
...
}
exCommon.configureApp({
name: 'other',
loadDefinition: loadDefinition,
parseUpdate: parseUpdate
})
Note that exhibitera_app_common.js
is a JavaScript module, so your file must also be a module.
Definitions
Definitions are user-provided configuraitons for your app. Users can use the Other App setup page in Exhibitera Apps to pass parameters to your app. Based on those parameters, you can configure the app as needed. These parameters are given in the parameters
field of the defintion:
{
...
parameters: {
'parameter 1': 'value 1',
'parameter 2': 'value 2'
},
...
}
You can ignore the other fields in the definition, as they are for interal Exhibitera use.
Updates
If your user is using Hub, your app will check in with the server every five seconds. This updates the Hub web console and retrieves any updates from the server.
Interaction status
Your app can communicate whether it is in active use by setting the value of exCommon.config.currentInteraction
. Set the value to true
when interaction begins and false
when it ends. One common way of defining "ends" is when the attractor is shown again. Properly setting this variable helps your user understand how the app is being used and enables them to collect analytics.
Responding to commands
Hub may send a command in response to a user action, an event in the schedule, or another app. Built-in commands, such as refreshing, restarting, and shutting down, are handled automatically by Exhibitera.
Using the parseUpdate()
function, your app can respond to custom commands.
Reading and writing local data
You can read and write local data by using exCommon.makeHelperRequest()
. For example, here is the code used to save votes from Voting Kiosk:
exCommon.makeHelperRequest(
{
method: 'POST',
endpoint: '/data/write',
params: {
name: 'votingData',
data: {
option1: 5,
option2: 8
}
}
})
makeHelperRequest()
returns a Promise that resolves with two fields, the boolean success
and the string reason
. If the write fails, reason
will provide helpful details.
/data/write
POST
Write a JavaScript object to disk. Each request will write one line of JSON to the file. The user can download the file as a CSV spreadsheet from the Exhibitera Apps configuration page.
{
data: {
key1: 'value1',
'key 2': ['value 2', 'value 3']
},
name: 'myDataFile'
}
data
Object
A JSON-serializable object.
name
String
A string filename without an extension. The extension '.txt'
will be appended.
/data/writeRawText
POST
Write the given text to file for later retrieval. If you wish to write JSON, you must call JSON.stringify()
yourself first.
{
text: 'A string of text',
mode: 'a',
name: 'myDataFile'
}
text
String
The text to be written to file.
mode
String
Pass 'a'
(default) to append to the file or 'w'
to overwrite the file.
name
String
A string filename without an extension. The extension '.txt'
will be appended.
/data/getRawText
POST
Retrieve a previously-written data file.
{
name: 'myDataFile'
}
name
String
A string filename without an extension. The extension '.txt'
will be appended.
Building a non-broswer app
When building an app using Python, Java, .NET, etc., you must communicate with Hub manually.
Ping
Exhibitera uses a client-server model. To connect your app to Exhibitera Hub, you should send a JSON object to the server every five seconds. Exhibitera calls this a ping
. The ping
object should have the following format and be sent as a POST
request to the endpoint /system/ping
:
{
currentInteraction: true,
helperAddress: '192.168.1.27:8000',
permissions: {
audio: true,
refresh: true,
restart: true,
shutdown: false,
sleep: false
},
uuid: '9e325f88-2f21-4a64-b9ef-f39d549f140f'
}
currentInteraction
Boolean
Boolean value that should be true
if the user is currently interacting with the app or false
if they are not (or this is not an interactive app).
helperAddress
String
The helperAddress
is the IP address and port of a webserver run by your application that can receive commands.
permissions
Object
A dictionary defining how Hub may command the app.
audio
Boolean
A boolean value giving whether Hub can mute/unmute the app.
refresh
Boolean
A boolean value giving whether Hub can ask the app to refresh its state. The result should be equivilent to pressing refresh in a browser.
restart
Boolean
A boolean value giving whether Hub may ask the app to restart the underlying computer.
shutdown
Boolean
A boolean value giving whether Hub may ask the app to shut down the underlying computer.
sleep
Boolean
A boolean value giving whether Hub may ask the app to put the display to sleep.
uuid
String
String value representing a totally-unique identifier. Each installation of your app should use a different uuid
, but the uuid
must be consistent between app sessions. Exhibitera Hub interprets each uuid
as an entirely different physical installation.
Ping response
When Hub receives a ping
, it will respond with a JSON object. That object will have the following structure:
{
app_id: 'other',
app_name: '',
commands: [],
current_exhibit: 'An Exhibit',
definition: '08a1ad7a-c40d-40c7-8b06-c0bd878a9921',
description: 'Some user-provided text describing this interactive.',
error: '{}',
maintenance_status: 'On floor, working',
permissions: {
audio: true,
refresh: true,
restart: true,
shutdown: false,
sleep: false
}
}
Most of these fields are for internal Exhibitera use. However, your app should respond to the follwoing fields:
commands
Array
An array of string values representing commands from Hub.
'refresh_page'
Your app should respond by rebuilding its content or reloading its state to an initial default. This should behave similarly to how pressing reload on a webpage does.
'restart'
Your app should initiate a reboot of the underlying PC.
'shutdown'
or 'power_off'
Your app should initiate a shut down of the underlying PC.
'sleepDisplay'
Your app should attempt to place the computer's display to sleep.
'wakeDisplay'
or 'power_on'
Your app should wake the computer's display.
permissions
Object
This dictionary represents the user's desired permissions. If reasonable, you should update your internal permissions to align with these.
audio
Boolean
If audio
is true
, your app should allow audio (unmute); if false
, it should mute the audio.