adaptorex
Version:
Connect all your live interactive storytelling devices and software
221 lines (207 loc) • 8.04 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
}