adaptorex
Version:
Connect all your live interactive storytelling devices and software
198 lines (166 loc) • 5.58 kB
JavaScript
/**
*
* This plugin summons many typical communication protocols. It allows to connect create different types of connections and to address them in levels.
* It adds a send action to cue creation that allows to send messages to all previously created devices.
* It allows to switch or listen based on the state of the created devices.
*
*
* @requires device
* @requires plugin
*
* @module devices/devices
* @copyright Lasse Marburg 2021
* @license MIT
*/
const deviceModule = require("./device.js")
const {Plugin} = require("../plugin.js")
var schema = require("./schema.json")
class Devices extends Plugin {
constructor() {
super(schema)
}
async setup(config, game) {
this.update(config.settings)
await super.setup(config, game)
this.schema.actions.send.test = "Hallo"
this.addTemplate("send", (payload, action) => {
let subtitle = `To device ${payload.to}`
let body = [{text:`${payload.method || ""} ${payload.path || ""} ${payload.message || ""}`}]
return {subtitle:subtitle, body:body}
})
for(let collection in this.schema.collections) {
this[collection].add = async (device) => {
this[collection].items[device._id] = deviceModule.getDevice(device, {name: collection, db_coll: this.game.db["devices_" + collection], emitUpdate: this[collection].emitItemUpdate.bind(this[collection])}, config, game)
this[collection].items[device._id].ready = true
await this.addDeviceToSchema(device)
}
this[collection].update = (item, item_doc) => {
if(item.name != item_doc.name) {
this.addDeviceToSchema(item_doc, item)
}
}
this[collection].remove = async (item) => {
try {
await item.close()
} catch (error) {
log.error(this.name, error)
}
delete this[collection].items[item._id]
let index = this.schema.actions.send.properties.to.enum.indexOf(item.name)
this.schema.actions.send.properties.to.enum.splice(index, 1)
await this.schemaUpdate(this.schema)
}
await this[collection].loadItems()
}
await this.load({})
deviceModule.setVirtualMidiPort(this.name)
return this.schema
}
async addDeviceToSchema(device, legacy_device) {
if(device.settings.to_device || (!device.settings.to_device && !device.settings.from_device)) {
if(legacy_device) {
let index = this.schema.actions.send.properties.to.enum.indexOf(legacy_device.name)
this.schema.actions.send.properties.to.enum.splice(index, 1, device.name)
} else {
this.schema.actions.send.properties.to.enum.push(device.name)
}
}
await this.schemaUpdate(this.schema)
}
async load(setup) {
let level = await this.game.db.levels.distinct('name',{})
this.schema.definitions.init.properties.level.enum = level
for(let collection in this.schema.collections) {
this.schema.collections[collection].properties.init = this.schema.definitions.init
}
try {
let serialports = await deviceModule.getSerialPorts()
this.schema.collections.serial.properties.settings.properties.port.enum = serialports
} catch (error) {
log.error(this.name, "Error when finding serial ports.")
log.error(this.name, error)
delete this.schema.collections.serial
}
try {
let midiports = await deviceModule.getMidiPorts()
} catch (error) {
log.error(this.name, error)
delete this.schema.collections.midi
}
await this.schemaUpdate(this.schema)
setup.schema = this.schema
return setup
}
update(settings) {
if(settings.hasOwnProperty("midi")) {
if(settings.midi.active) {
deviceModule.activateMidi()
} else {
deviceModule.deactivateMidi()
}
}
}
/**
* Find device by name.
*
* Search for device across all device collections.
*
* @param {string} name device name property
* @returns {Object} device item
*/
findDevice(name) {
for(let collection in this.schema.collections) {
if(this[collection].findItem('name', name)) {
return this[collection].findItem('name', name)
}
}
}
/**
* Send payload to device
*
* if device send() returns a value, its stored in session document.
*
*/
async send(data, session) {
if(typeof data.to === "string") {
var device = this.findDevice(data.to)
} else if(typeof data.to === "object") {
var device = this.findDevice(data.to.name)
}
if(!device) {
throw new adaptor.InvalidError(data.to + " is not a valid device.")
}
data.message = session.variables.parseJSON(data.message)
let result = await device.send(data.message,{path:data.path,is_float:data.is_float,method:data.method})
if(result) {
let store = {}
store[device.name] = result
await session.variables.store(store)
}
}
command(input) {
switch(input[0]) {
case "ports":
deviceModule.getPorts()
.then(ports => {
log.info(this.name, ports)
})
.catch(function(error){
log.error(this.name, error)
}.bind(this))
break
case "midi":
if(input[1] == "on") {
deviceModule.activateMidi()
log.info(this.name, "please restart adaptor:ex to reactivate midi")
} else if(input[1] == "off") {
deviceModule.deactivateMidi()
}
break
default:
super.command(input)
break
}
}
}
module.exports.Plugin = Devices