Skip to content

TypeScript VISA library for instrument communication (PyVISA-like)

License

Notifications You must be signed in to change notification settings

jvanderberg/visa-ts

Repository files navigation

visa-ts

npm version Build Status Coverage License: MIT

TypeScript VISA (Virtual Instrument Software Architecture) library for instrument communication.

A PyVISA-inspired library for controlling test and measurement instruments from Node.js/TypeScript.

Features

  • PyVISA-compatible API — Familiar patterns for lab automation developers
  • Multiple transports — USB-TMC, Serial, TCP/IP (LXI)
  • Device simulation — Test without hardware using simulated PSU, Load, and DMM
  • Circuit simulation — Simulated devices interact with realistic physics
  • TypeScript-first — Full type safety and autocomplete
  • Result-based errors — No exceptions, explicit error handling
  • SCPI utilities — Parse responses, binary blocks, etc.

Installation

npm install visa-ts

This includes serialport and usb as dependencies for Serial and USB-TMC support.

Quick Start

import { createResourceManager } from 'visa-ts';

// Create resource manager
const rm = createResourceManager();

// List connected USB instruments
const resources = await rm.listResources('USB?*::INSTR');
console.log(resources);
// ['USB0::0x1AB1::0x04CE::DS1ZA123456789::INSTR']

// Open instrument
const result = await rm.openResource('USB0::0x1AB1::0x04CE::DS1ZA123456789::INSTR');
if (!result.ok) {
  console.error('Failed to open:', result.error);
  return;
}
const instr = result.value;

// Configure
instr.timeout = 5000;

// Query device identity
const idn = await instr.query('*IDN?');
if (idn.ok) {
  console.log(idn.value);  // 'RIGOL TECHNOLOGIES,DS1054Z,...'
}

// Close
await instr.close();
await rm.close();

Resource String Formats

Type Format Example
USB-TMC USB[board]::vendor::product::serial::INSTR USB0::0x1AB1::0x04CE::DS1ZA123456789::INSTR
Serial ASRL[port]::INSTR ASRL/dev/ttyUSB0::INSTR
TCP/IP TCPIP[board]::host::port::SOCKET TCPIP0::192.168.1.100::5025::SOCKET

Discovery

// USB - automatic enumeration
const usbDevices = await rm.listResources('USB?*::INSTR');

// Serial - lists available ports
const serialPorts = await rm.listResources('ASRL?*::INSTR');

// TCP/IP - manual (requires known IP)
const instr = await rm.openResource('TCPIP0::192.168.1.100::5025::SOCKET');

API Reference

ResourceManager

  • listResources(query?: string) — List available instruments
  • openResource(resourceString, options?) — Open connection to instrument
  • close() — Close all connections

MessageBasedResource

  • query(cmd) — Write command and read response
  • queryBinaryValues(cmd, datatype?) — Query binary data
  • write(cmd) — Write command (no response)
  • read() — Read response
  • clear() — Clear device buffers
  • close() — Close connection

Attributes

  • timeout — I/O timeout in milliseconds
  • readTermination — Read termination character
  • writeTermination — Write termination character

Simulation

Test your instrument control code without physical hardware:

import { createResourceManager, createSimulatedPsu } from 'visa-ts';

// Create resource manager and register a simulated PSU
const rm = createResourceManager();
rm.registerSimulatedDevice('PSU', createSimulatedPsu());

// Use it like real hardware
const result = await rm.openResource('SIM::PSU::INSTR');
if (result.ok) {
  const psu = result.value;
  await psu.write('VOLT 12.0');
  await psu.write('OUTP ON');
  const voltage = await psu.query('MEAS:VOLT?');
  console.log(voltage.value); // '12.000'
}

Available simulated devices: createSimulatedPsu(), createSimulatedLoad(), createSimulatedDmm()

When multiple simulated devices are connected, circuit simulation makes them interact realistically (e.g., PSU current limiting affects Load measurements).

Middleware

Add logging, retries, or custom transformations to SCPI communication:

import { withMiddleware, loggingMiddleware, retryMiddleware } from 'visa-ts';

// Wrap resource with middleware
const debugResource = withMiddleware(resource, [
  loggingMiddleware(),                    // Log all traffic
  retryMiddleware({ maxRetries: 3 }),     // Auto-retry on failure
]);

// Use wrapped resource with drivers or directly
const idn = await debugResource.query('*IDN?');
// Console: > *IDN?
// Console: < RIGOL TECHNOLOGIES,DS1054Z,...

Built-in middleware:

Function Description
loggingMiddleware(options?) Log commands/responses with optional timestamps
retryMiddleware(options?) Retry failed operations with configurable attempts
responseTransformMiddleware(fn) Transform responses (e.g., trim whitespace)
commandTransformMiddleware(fn) Transform commands before sending

Custom middleware:

import type { Middleware } from 'visa-ts';

const myMiddleware: Middleware = async (cmd, next) => {
  console.log('Sending:', cmd);
  const result = await next(cmd);
  if (result.ok) console.log('Received:', result.value);
  return result;
};

Comparison to PyVISA

PyVISA visa-ts
rm = pyvisa.ResourceManager() rm = createResourceManager()
rm.list_resources() await rm.listResources()
instr = rm.open_resource(...) result = await rm.openResource(...)
instr.query('*IDN?') await instr.query('*IDN?')
instr.timeout = 5000 instr.timeout = 5000

Key differences:

  • Factory functions instead of classes (createResourceManager() not new ResourceManager())
  • All I/O operations are async (return Promises)
  • Errors returned as Result<T, Error> instead of exceptions
  • TypeScript provides full type safety

License

MIT

About

TypeScript VISA library for instrument communication (PyVISA-like)

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •