ide_qsys
v3.1.2
Published
Enhanced Q-Sys core interaction library with component management, script monitoring, and advanced diagnostics
Maintainers
Readme
ide_qsys
A Node.js library for programmatically managing Q-SYS cores and Lua scripts. Deploy code to multiple systems, monitor script health, sync with files, and automate your Q-SYS infrastructure.
Installation
npm install ide_qsysQuick Start
Basic Connection
import Core from 'ide_qsys';
const { username, pin } = process.env;
const core = new Core({
ip: '192.168.1.100',
username,
pin,
verbose: false // Enable verbose logging (default: false)
});
await core.connect();
const components = await core.getComponents();
console.log(`Found ${components.length} components`);
await core.disconnect();Q-SYS Component Configuration
Before you can access script components via QRC, they must be configured for script access in Q-SYS Designer.
Enabling Script Access
In Q-SYS Designer, for each script component you want to access:
- Select the script component
- In the Properties panel, set "Script Access" dropdown to anything other than "None" (which is the default)
- The "Code Name" field shows the component name you'll use in your code

Important Notes:
- Script Access = "None": Component cannot be accessed via QRC
- Script Access = "All" or other options: Component can be accessed via QRC
- The "Code Name" field value is what you use as the
componentNameparameter in your API calls
// If your component's "Code Name" is "Main"
const components = await core.getComponents();
const code = await core.getCode('Main'); // Use the Code Name hereAuthentication
Setting Up Q-SYS Administrator Credentials
The username and PIN are configured in Q-SYS Administrator. You need to create a user with External Control Protocol permissions:

In Q-SYS Administrator:
- Go to the user management section
- Create or edit a user (e.g., "admin")
- Set a PIN (e.g., "1234")
- Enable "External Control Protocol" permissions
- Enable "File Management Protocol" if you need file operations
Constructor Options
const { username, pin } = process.env;
const core = new Core({
ip: '192.168.1.100', // Required: Q-SYS Core IP address
username, // Required: Username from Q-SYS Administrator
pin, // Required: PIN (also accepts 'password' or 'pw')
comp: 'Main', // Optional: Default component name
verbose: false // Optional: Enable debug logging
});Authentication Error Examples
Wrong credentials:
// This will throw an error
const { username } = process.env;
const core = new Core({
ip: '192.168.1.100',
username,
pin: 'wrong_pin' // Intentionally wrong PIN for demonstration
});
try {
await core.connect();
} catch (error) {
console.error(error.message); // "QRC authentication failed for 192.168.1.100: Logon required"
}Missing credentials:
// This will throw an error
const core = new Core({
ip: '192.168.1.100'
// Missing username and pin
});
try {
await core.connect();
} catch (error) {
console.error(error.message); // "QRC authentication failed for 192.168.1.100: Logon required"
}Connection Management
Session-Based (Recommended for Multiple Operations)
const { username, pin } = process.env;
const core = new Core({ ip: '192.168.1.100', username, pin });
await core.connect();
// Perform multiple operations efficiently
const components = await core.getComponents();
const logs = await core.collectLogs('Main');
const code = await core.getCode('Main');
await core.disconnect();Single-Shot Operations (Auto Connect/Disconnect)
const { username, pin } = process.env;
const core = new Core({ ip: '192.168.1.100', username, pin });
// These methods handle connection automatically
const components = await core.getComponentsSync();
const errors = await core.getScriptErrorsSync();API Reference
Connection Methods
connect()
Establishes a persistent connection to the Q-SYS core.
await core.connect();disconnect()
Closes the connection to the Q-SYS core.
const disconnected = await core.disconnect();
console.log(`Successfully disconnected: ${disconnected}`); // true if successful
// Check connection status anytime
console.log(`Currently connected: ${core.connected}`); // boolean propertyReturns: boolean - true if successfully disconnected, false otherwise
Component Methods
getComponents() / getComponentsSync()
Returns an array of all components in the Q-SYS design.
// Session-based
await core.connect();
const components = await core.getComponents();
await core.disconnect();
// Single-shot
const components = await core.getComponentsSync();Returns: Array of component objects with Name and Type properties.
getControls(componentName, callback) / getControlsSync(componentName)
Gets all controls for a specific component.
// Session-based with callback
await core.connect();
await core.getControls('Main', (error, controls) => {
if (error) console.error(error);
else console.log(controls);
});
await core.disconnect();
// Single-shot
const controls = await core.getControlsSync('Main');Parameters:
componentName(string): Name of the componentcallback(function, optional): Callback function for session-based method
Returns: Array of control objects.
getComponent(componentName, controlName, callback) / getComponentSync(componentName, controlName)
Gets the value of a specific control.
// Session-based
await core.connect();
const value = await core.getComponent('Main', 'Status');
await core.disconnect();
// Single-shot
const value = await core.getComponentSync('Main', 'Status');Parameters:
componentName(string): Name of the componentcontrolName(string): Name of the controlcallback(function, optional): Callback function for session-based method
Returns: Control value object.
setComponent(componentName, controlName, value, callback) / setComponentSync(componentName, controlName, value)
Sets the value of a specific control.
// Session-based
await core.connect();
await core.setComponent('Main', 'reload', 1);
await core.disconnect();
// Single-shot
await core.setComponentSync('Main', 'reload', 1);Parameters:
componentName(string): Name of the componentcontrolName(string): Name of the controlvalue(any): Value to setcallback(function, optional): Callback function for session-based method
Script Management Methods
getScriptErrors(options, callback) / getScriptErrorsSync(options)
Gets script errors for components with enhanced feedback.
// Session-based - specific component
await core.connect();
const errors = await core.getScriptErrors({ scriptName: 'Main' });
console.log(errors.Found); // true/false - component exists
console.log(errors.Message); // descriptive message
console.log(errors.Value); // error count (0 if no errors)
// Session-based - all components
const allErrors = await core.getScriptErrors();
console.log(allErrors.summary.totalScriptComponents); // total script components found
console.log(allErrors.summary.componentsWithErrors); // how many have errors
console.log(allErrors.errors); // array of components with errors
await core.disconnect();
// Single-shot
const errors = await core.getScriptErrorsSync({ scriptName: 'Main' });Parameters:
options(object, optional):scriptName(string): Specific script name to check
callback(function, optional): Callback function for session-based method
Returns:
- With
scriptName: Object withFound,Message,Value,Details,Componentproperties - Without
scriptName: Object witherrorsarray andsummaryobject
restartScript(componentName, callback) / restartScriptSync(componentName)
Restarts a script component.
// Session-based
await core.connect();
await core.restartScript('Main');
await core.disconnect();
// Single-shot
await core.restartScriptSync('Main');Parameters:
componentName(string): Name of the script componentcallback(function, optional): Callback function for session-based method
collectLogs(componentName, callback) / collectLogsSync(componentName)
Collects console logs from a script component.
// Session-based
await core.connect();
const logs = await core.collectLogs('Main');
await core.disconnect();
// Single-shot
const logs = await core.collectLogsSync('Main');Parameters:
componentName(string): Name of the script componentcallback(function, optional): Callback function for session-based method
Returns: Array of log strings with timestamps removed.
Code Management Methods
getCode(componentName, callback) / getCodeSync(componentName)
Gets the Lua code from a script component.
// Session-based
await core.connect();
const code = await core.getCode('Main');
await core.disconnect();
// Single-shot
const code = await core.getCodeSync('Main');Parameters:
componentName(string): Name of the script componentcallback(function, optional): Callback function for session-based method
Returns: String containing the Lua code.
updateCode(componentName, code, callback)
Updates the Lua code in a script component and returns deployment information.
await core.connect();
const result = await core.updateCode('Main', luaCode);
console.log(`Errors: ${result.deployment.errorCount}`);
console.log(`Logs: ${result.deployment.logs.join(', ')}`);
await core.disconnect();Parameters:
componentName(string): Name of the script componentcode(string): Lua code to deploycallback(function, optional): Callback function
Returns: Object with deployment information including:
deployment.componentName(string): Component namedeployment.codeLength(number): Length of deployed codedeployment.errorCount(number): Number of errors after deploymentdeployment.errorDetails(object): Error details if anydeployment.logs(array): Console logs after deploymentdeployment.timestamp(string): Deployment timestamp
Production Methods
Multi-Core Deployment
Core.deployToMultipleCores(coreConfigs, componentName, code, options)
Static method to deploy one script to multiple Q-SYS cores.
const { username, pin } = process.env;
const coreConfigs = [
{ ip: '192.168.1.100', username, pin, systemName: 'Core1' },
{ ip: '192.168.1.101', username, pin, systemName: 'Core2' },
{ ip: '192.168.1.102', username, pin, systemName: 'Core3' }
];
const result = await Core.deployToMultipleCores(
coreConfigs,
'Main',
fs.readFileSync('./scripts/main.lua', 'utf8'),
{ validateFirst: true, rollbackOnError: true }
);Parameters:
coreConfigs(array): Array of core configuration objectscomponentName(string): Name of the script componentcode(string): Lua code to deployoptions(object, optional):validateFirst(boolean): Validate code before deploymentrollbackOnError(boolean): Rollback on deployment errors
Returns: Object with deployment results for each core.
File Operations
loadScriptFromFile(filePath, componentName, options)
Loads Lua code from a file and deploys it to a component.
await core.connect();
const result = await core.loadScriptFromFile('./scripts/main.lua', 'Main');
console.log(`Deployed: ${result.codeLength} characters, ${result.errorCount} errors`);
await core.disconnect();Parameters:
filePath(string): Path to the Lua filecomponentName(string): Name of the script componentoptions(object, optional): Additional options
Returns: Object with deployment information.
saveScriptToFile(componentName, filePath, options)
Saves Lua code from a component to a file.
await core.connect();
await core.saveScriptToFile('Main', './backup/main.lua', {
createDir: true,
backup: true
});
await core.disconnect();Parameters:
componentName(string): Name of the script componentfilePath(string): Path where to save the fileoptions(object, optional):createDir(boolean): Create directory if it doesn't existbackup(boolean): Create backup if file exists
syncScriptWithFile(componentName, filePath, direction, options)
Synchronizes a script component with a file.
await core.connect();
// Check sync status without making changes
const status = await core.syncScriptWithFile('Main', './scripts/main.lua', 'check');
console.log(status.message); // "File (3252 chars) and component (3232 chars) differ"
// Force file to component
await core.syncScriptWithFile('Main', './scripts/main.lua', 'push', {
createBackup: true // Create backup before overwriting (default: true)
});
// Force component to file
await core.syncScriptWithFile('Main', './scripts/main.lua', 'pull', {
createBackup: true // Create backup before overwriting (default: true)
});
await core.disconnect();Parameters:
componentName(string): Name of the script componentfilePath(string): Path to the filedirection(string): 'check', 'push', or 'pull'options(object, optional):createBackup(boolean): Create backup files before overwriting (default: true)
Directions:
'check': Compare file and component, return status information'push': Update component with file content (file → component)'pull': Update file with component content (component → file)
Returns: Object with sync information:
success(boolean): Operation success statusaction(string): 'check', 'push', or 'pull'direction(string): Sync direction used (for push/pull)message(string): Descriptive status messageinSync(boolean): Whether file and component are identical (check only)status(string): Sync status - 'in-sync', 'out-of-sync', 'file-missing', 'component-missing', 'both-missing' (check only)fileSample(string): First 100 characters of file (check only, when different)componentSample(string): First 100 characters of component (check only, when different)codeLength(number): Length of synced code (push/pull only)backupPath(string): Path to backup file if created (pull only)
backupAllScripts(backupDir, options)
Backup all control scripts from the system to a designated folder.
const { username, pin } = process.env;
const core = new Core({ ip: '192.168.1.100', username, pin });
await core.connect();
// Auto-generated backup directory (default - no timestamp, will overwrite)
const result = await core.backupAllScripts();
// Creates: ./backup_192-168-1-100/
// Auto-generated with timestamp (prevents overwrites)
const result = await core.backupAllScripts(null, { timestamp: true });
// Creates: ./backup_192-168-1-100_2025-11-05T17-33-26-480Z/
// Specific backup directory
const result = await core.backupAllScripts('./backups/core1');
// Advanced backup with options
const result = await core.backupAllScripts('./backups/core1', {
createDir: true, // Create directory if it doesn't exist (default: true)
includeEmpty: false, // Include scripts with empty code (default: false)
systemName: 'Core1', // Custom system name for manifest (default: IP)
timestamp: false // Include timestamp in auto-generated directory names (default: false)
});
console.log(`Backed up ${result.scriptCount} scripts to ${result.backupDir}`);
console.log(`Scripts: ${result.scripts.join(', ')}`);
await core.disconnect();Parameters:
backupDir(string, optional): Directory path where scripts will be saved (default: auto-generated folder)options(object, optional):createDir(boolean): Create backup directory if it doesn't exist (default: true)includeEmpty(boolean): Include scripts with empty/blank code (default: false)systemName(string): Custom system name for manifest (default: uses systemName or IP)timestamp(boolean): Include timestamp in auto-generated directory names (default: false)
Returns: Object with backup information:
success(boolean): Backup operation success statusbackupDir(string): Path to backup directoryscriptCount(number): Number of scripts backed uptotalComponents(number): Total components found in systemmanifest(string): Path to backup manifest filescripts(array): Array of script names that were backed up
Files Created:
{ComponentName}.lua- Individual script filesbackup_manifest.json- Backup metadata and script inventory
Health Monitoring
Core.monitorScriptHealth(coreConfigs, scriptNames, options)
Static method to monitor script health across multiple cores.
const { username, pin } = process.env;
const coreConfigs = [
{ ip: '192.168.1.100', username, pin, systemName: 'Core1' },
{ ip: '192.168.1.101', username, pin, systemName: 'Core2' },
{ ip: '192.168.1.102', username, pin, systemName: 'Core3' }
];
const healthReport = await Core.monitorScriptHealth(
coreConfigs,
['Main', 'Module'],
{
includeErrors: true,
includeStatus: true,
includeLogs: true,
logLines: 5
}
);
console.log(`Overall health: ${healthReport.summary.healthPercentage}%`);
console.log(`Cores with issues: ${healthReport.summary.coresWithIssues}`);Parameters:
coreConfigs(array): Array of core configuration objectsscriptNames(array): Array of script names to monitoroptions(object, optional):includeErrors(boolean): Include error informationincludeStatus(boolean): Include status informationincludeLogs(boolean): Include log informationlogLines(number): Number of log lines to include
Returns: Object with health report and summary.
Best Practices
- Always disconnect: Ensure sessions are properly closed
- Use try/finally: Guarantee cleanup even on errors
- Batch operations: Use sessions for multiple operations
- Single-shot for simple tasks: Use sync methods for one-off operations
const { username, pin } = process.env;
const core = new Core({ ip: '192.168.1.100', username, pin });
try {
await core.connect();
// Multiple operations
const components = await core.getComponents();
const errors = await core.getScriptErrors();
const logs = await core.collectLogs('Main');
} catch (error) {
console.error('Session operations failed:', error);
} finally {
await core.disconnect(); // Always cleanup
}Requirements
- Node.js 14+ (ES modules support)
- Q-SYS Core with QRC enabled
- Network access to Q-SYS Core on port 1710
License
ISC
Contributing
Issues and pull requests welcome at GitHub repository.
