npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

ide_qsys

v3.1.2

Published

Enhanced Q-Sys core interaction library with component management, script monitoring, and advanced diagnostics

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_qsys

Quick 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:

  1. Select the script component
  2. In the Properties panel, set "Script Access" dropdown to anything other than "None" (which is the default)
  3. The "Code Name" field shows the component name you'll use in your code

Q-SYS Component Configuration

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 componentName parameter 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 here

Authentication

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:

Q-SYS Administrator Example

In Q-SYS Administrator:

  1. Go to the user management section
  2. Create or edit a user (e.g., "admin")
  3. Set a PIN (e.g., "1234")
  4. Enable "External Control Protocol" permissions
  5. 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 property

Returns: 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 component
  • callback (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 component
  • controlName (string): Name of the control
  • callback (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 component
  • controlName (string): Name of the control
  • value (any): Value to set
  • callback (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 with Found, Message, Value, Details, Component properties
  • Without scriptName: Object with errors array and summary object

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 component
  • callback (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 component
  • callback (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 component
  • callback (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 component
  • code (string): Lua code to deploy
  • callback (function, optional): Callback function

Returns: Object with deployment information including:

  • deployment.componentName (string): Component name
  • deployment.codeLength (number): Length of deployed code
  • deployment.errorCount (number): Number of errors after deployment
  • deployment.errorDetails (object): Error details if any
  • deployment.logs (array): Console logs after deployment
  • deployment.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 objects
  • componentName (string): Name of the script component
  • code (string): Lua code to deploy
  • options (object, optional):
    • validateFirst (boolean): Validate code before deployment
    • rollbackOnError (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 file
  • componentName (string): Name of the script component
  • options (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 component
  • filePath (string): Path where to save the file
  • options (object, optional):
    • createDir (boolean): Create directory if it doesn't exist
    • backup (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 component
  • filePath (string): Path to the file
  • direction (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 status
  • action (string): 'check', 'push', or 'pull'
  • direction (string): Sync direction used (for push/pull)
  • message (string): Descriptive status message
  • inSync (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 status
  • backupDir (string): Path to backup directory
  • scriptCount (number): Number of scripts backed up
  • totalComponents (number): Total components found in system
  • manifest (string): Path to backup manifest file
  • scripts (array): Array of script names that were backed up

Files Created:

  • {ComponentName}.lua - Individual script files
  • backup_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 objects
  • scriptNames (array): Array of script names to monitor
  • options (object, optional):
    • includeErrors (boolean): Include error information
    • includeStatus (boolean): Include status information
    • includeLogs (boolean): Include log information
    • logLines (number): Number of log lines to include

Returns: Object with health report and summary.

Best Practices

  1. Always disconnect: Ensure sessions are properly closed
  2. Use try/finally: Guarantee cleanup even on errors
  3. Batch operations: Use sessions for multiple operations
  4. 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.