adaptorex
Version:
Connect all your live interactive storytelling devices and software
244 lines (231 loc) • 7.05 kB
JavaScript
const action_schema = {
setLights: {
title: "Set Lights",
description: "Change the DMX values of your DMX-USB-PRO box.",
documentation:
"https://docs.adaptorex.org/basics/actions/usb-dmx-pro/setLights.html",
anyOf: [
{
title: "Values",
type: "array",
format: "table",
default: [{ channel: 1, value: "0" }],
items: {
type: "object",
additionalProperties: false,
properties: {
channel: {
type: "integer",
default: 1,
minimum: 1,
maximum: 512
},
value: {
type: "string",
default: 0
}
},
required: ["channel", "value"]
}
},
{
title: "Slider",
type: "array",
format: "table",
items: {
type: "object",
additionalProperties: false,
properties: {
channel: {
type: "integer",
default: 1,
minimum: 1,
maximum: 512
},
value: {
type: "integer",
format: "range",
default: 0,
minimum: 0,
maximum: 255
}
},
required: ["channel", "value"]
}
}
]
}
}
const settings_schema = {
type: "object",
title: "DMX USB Pro Class Settings",
required: ["serialPort"],
default: { serialPort: "", autoConnectOnStart: true },
additionalProperties: false,
properties: {
serialPort: {
type: "string",
enum: ["eins", "zwei"]
},
autoConnectOnStart: {
// would be nicer to just do this via HTML?
type: "boolean"
}
}
}
const DMX = require("./dmx")
try {
var { SerialPort } = require("serialport")
} catch (e) {
log.error(
"dmx-usb",
"cannot require serialport. Probably no serialport available on the server running adaptor"
)
throw e // TODO: throw adaptor error so frontend gets 4xx instead of 500 response
}
const plugin = require("../plugin.js")
class myPlugin extends plugin.Plugin {
constructor() {
super()
this.action_schema = adaptor.deepClone(action_schema)
this.schema.actions = this.action_schema
this.settings_schema = adaptor.deepClone(settings_schema)
this.settings = null
this.myDMX = new DMX() // TODO: catch Serial and DMX errors --> how?
}
////////////// LIFECYCLE HOOKS PLUGIN ////////////////////////
/////////////////////////////////////////////////////////////
async setup(config, game) {
// LIFECYCLE HOOK
super.setup(config, game)
this.addTemplate("setLights", (payload, action) => {
const title = `dmx-usb-pro ${action.name}`
let subtitle
const body = [{ text: "" }]
for (let i = 0; i < payload.length; i++) {
body[0]["text"] += `${payload[i].channel}: ${payload[i].value}`
if (i < payload.length - 1) {
body[0]["text"] += ", "
}
}
return { title, subtitle, body }
})
log.info("dmx-usb setup", "STARTING ####", config.settings)
this.connected = false
await this.getSerialPorts()
this.settings = config.settings
if (config.settings.autoConnectOnStart) {
this.connectDMX(config)
}
log.info("dmx-usb settings schema", this.settings_schema.plugins)
return { actions: this.action_schema, settings: this.settings_schema }
}
async update(updateData) {
// LIFECYCLE HOOK
log.info("dmx-usb update", updateData)
if (this.settings.serialPort != updateData.serialPort) {
this.settings = updateData
this.connect()
} else {
this.settings = updateData // update Schema data
}
}
async load(plugindata) {
// LIFECYCLE HOOK on POST operator {game}/{plugin}/_load // middleware function // LASSE BUILDS THIS
await this.getSerialPorts()
plugindata.schema.settings = this.settings_schema
plugindata.connected = this.connected
return plugindata
}
disconnect() {
// LIFECYCLE HOOK // TODO:TEST
log.info("dmx-usb disconnect", this.connected)
this.closeSerial()
this.connected = false
log.info("dmx-usb disconnect done", this.connected)
return { connected: this.connected }
}
connect() {
// LIFECYCLE HOOK
log.info("dmx-usb connect", this.connected)
this.closeSerial()
// TODO: put in connectDMX function below
// TODO: use .open() async function and await it to get return values
this.myDMX.addUniverse(
"one",
"enttec-usb-dmx-pro",
this.settings.serialPort
)
this.myDMX.universes.one.dev.on("error", (e) => {
log.error("dmx-usb", "serialPort lost connection", e)
this.connected = false
})
this.myDMX.universes.one.dev.on("open", () => {
this.myDMX.update("one", { 1: 0, 2: 0, 3: 0, 4: 0 }) // initializes black on channels 1-4*/
this.connected = true
log.info("dmx-usb connect done", this.connected)
})
// THIS IS A LIE. we don't know yet if its connected (need to maybe use .open() function and autoOpen:false)
return { connected: this.connected }
}
command() {
// LIFECYCLE HOOK
log.info("dmx-usb-class", "command not implemented")
}
setLights(params) {
// defined above in action_schema
let output = {}
for (let setLights of params) {
output[parseInt(setLights.channel)] = setLights.value
}
log.info("dmx-usb", output)
log.info("dmx-usb universe info:", Object.keys(this.myDMX.universes).length)
// check if already connected to a universe.
if (Object.keys(this.myDMX.universes).length > 0) {
this.myDMX.update("one", output)
} else {
log.error(
"dmx-usb",
"no serial connection established to DMX Box. no universe set."
)
}
}
/////////////////// HELPER FUNCTIONS ////////////////////////
/////////////////////////////////////////////////////////////
async getSerialPorts() {
await SerialPort.list().then((ports) => {
let portList = []
for (const port of ports) {
//log.info("dmx-usb","possible ports for DMX USB PRO Plugin:", port.path);
portList.push(port.path)
}
this.settings_schema.properties.serialPort.enum = portList // populate schema with list of ports.
log.info("dmx-usb portList scan", portList)
return portList
})
}
connectDMX(config) {
this.closeSerial()
this.myDMX.addUniverse(
"one",
"enttec-usb-dmx-pro",
config.settings.serialPort
)
this.myDMX.update("one", { 1: 0, 2: 0, 3: 0, 4: 0 }) // initializes black on channels 1-4
log.info("DMX OBJECT", this.myDMX.universes.one.dev.close)
this.connected = true
}
closeSerial() {
if (
this.myDMX &&
this.myDMX.universes.one &&
this.myDMX.universes.one.dev &&
this.myDMX.universes.one.dev.isOpen
) {
this.myDMX.universes.one.dev.close()
}
}
}
module.exports = {
Plugin: myPlugin
}