Skip to content

Advanced Communication

This page covers advanced USB communication methods, serial ports, and network sockets. For basic reads and writes see Writes and Reads.

Understanding the difference between USB transfer types will help you choose the right method and debug unexpected errors.

TypeMethodTypical sizeUse case
Interruptdevice.write() / device.read()3–64 bytesRGB data, small commands, keyboard/mouse input
Bulkdevice.write() / device.read()64–1025 bytesLCD images, firmware updates, large config blocks
Controldevice.send_report() / device.get_report() / device.control_transfer()32–192 bytesAuthentication, HID feature reports, device configuration

The same device.write() and device.read() functions are used for both interrupt and bulk transfers — the USB driver determines the type from the endpoint and packet size.


Sends a HID GET_INPUT_REPORT control transfer. Similar to device.get_report() but specifically requests an Input report rather than a Feature report. Use this when get_report() returns wrong data because the device separates its Input and Feature report types.

ParameterTypeDescriptionExample
DataArray1D ArrayReport request data[0x01]
LengthIntExpected report size in bytes64
ReturnTypeDescription
DataArray1D ArrayBytes received from the device
var inputData = device.input_report([0x01], 64);

Performs a direct bulk or interrupt transfer to a specific USB endpoint. Unlike device.write() and device.read() which use the endpoint selected by device.set_endpoint(), this lets you target any endpoint by address.

  • Endpoint addresses ending in 0x80 or higher are IN (device → host, read).
  • Endpoint addresses below 0x80 are OUT (host → device, write).
ParameterTypeDescriptionExample
EndpointHexUSB endpoint address0x81
DataArray1D ArrayData to send (OUT), or empty array (IN)[0x01, 0x02]
LengthIntTransfer size in bytes64
TimeoutIntMilliseconds before giving up100
ReturnTypeDescription
DataArray1D ArrayBytes received (IN transfers), or empty
// Write to endpoint 0x01
device.bulk_transfer(0x01, [0x00, 0x01, 0x02], 3, 100);
// Read from endpoint 0x81
var response = device.bulk_transfer(0x81, [], 64, 100);
// Large bulk write (e.g. LCD image data)
device.bulk_transfer(0x02, imageData, 1024, 500);

Low-level USB control transfer. Used for authentication handshakes, vendor-specific protocols, and cases where HID methods aren’t sufficient. This is a control transfer, not a bulk transfer.

ParameterTypeDescriptionExample
RequestTypeHexUSB request type bitmap (direction, type, recipient)0xA1
RequestHexRequest code (device-specific)0x01
ValueHexValue field0x0100
IndexIntInterface or endpoint index0x00
DataArray1D ArrayData to send (host-to-device), or empty[]
LengthIntExpected response length (device-to-host)192
TimeoutIntMilliseconds before giving up1000
ReturnTypeDescription
DataArray1D ArrayBytes received (device-to-host transfers)

Common RequestType values:

ValueDirectionTypeRecipientUse case
0x21Host → DeviceClassInterfaceHID SET_REPORT
0xA1Device → HostClassInterfaceHID GET_REPORT
0x80Device → HostStandardDeviceDescriptor reads
0x00Host → DeviceStandardDeviceStandard commands
// Read authentication token (device → host, class, interface)
var token = device.control_transfer(
0xA1, // Device-to-host, class, interface
0x01, // GET_REPORT
0x0100, // Report type (Feature) + report ID
0x00, // Interface 0
[], // No outbound data
192, // Expect 192 bytes back
1000 // 1 second timeout
);
// Send a feature report (host → device)
device.control_transfer(0x21, 0x09, 0x0300, 0, [0x03, 0x08, 0x32], 0, 500);

For serial/COM port devices, import the serial module and set your plugin’s Type() to "serial".

import { serial } from "@SignalRGB/serial";
export function Type() { return "serial"; }
serial.connect({
baudRate: 115200, // Default: 115200
parity: "None", // "None", "Even", "Odd", "Space", "Mark"
dataBits: 8, // 5, 6, 7, or 8
stopBits: "One" // "One", "OneAndHalf", "Two"
});
MethodDescriptionReturns
serial.connect(options?)Open the serial portbool
serial.disconnect()Close the serial portvoid
serial.isConnected()Check connection statebool
serial.write(data)Send databytes written
serial.read(maxBytes?, timeoutMs?)Read available bytes (default: all, 1000ms timeout)byte array
serial.readAll()Read all available bytes immediatelybyte array
serial.availablePorts()List available COM portsarray
serial.getPortName()Current port namestring
serial.getBaudRate()Current baud ratenumber
serial.getDeviceInfo()Port info with VID, PID, etc.object
import { serial } from "@SignalRGB/serial";
export function Type() { return "serial"; }
export function Initialize() {
if (!serial.connect()) {
device.log("Failed to connect to serial port");
return;
}
device.log(`Connected on ${serial.getPortName()} at ${serial.getBaudRate()} baud`);
}
export function Render() {
serial.write([0xFF, ...RGBData]);
}
export function Shutdown() {
serial.disconnect();
}

For network-connected devices, import the TCP or UDP module and set Type() to "network". Both modules use an event-based callback model.

import { tcp } from "@SignalRGB/tcp";
import { udp } from "@SignalRGB/udp";
export function Type() { return "network"; }
import { tcp } from "@SignalRGB/tcp";
let socket;
export function Initialize() {
socket = tcp.createSocket();
socket.on("connected", () => {
device.log("Connected");
socket.send([0x01, 0x02, 0x03]);
});
socket.on("message", (data) => {
device.log(`Received: ${data}`);
});
socket.on("error", (err) => {
device.log(`Error: ${err}`);
});
socket.connect("192.168.1.100", 8080);
}
export function Render() {
if (socket.state === socket.ConnectedState) {
socket.send(RGBData);
}
}
export function Shutdown() {
socket.close();
}

TCP Methods:

MethodDescription
tcp.createSocket()Create a new TCP socket
socket.connect(address, port)Connect to a host
socket.send(data)Send string or byte array
socket.bind(port)Bind to a local port
socket.close()Close the socket
socket.on(event, callback)Register an event handler

TCP Events: "connected", "disconnected", "message", "error"


import { udp } from "@SignalRGB/udp";
let socket;
export function Initialize() {
socket = udp.createSocket();
socket.on("message", (data) => {
device.log(`Received: ${data}`);
});
socket.connect("192.168.1.100", 21324);
}
export function Render() {
socket.send(RGBData);
}
export function Shutdown() {
socket.close();
}

UDP Methods:

MethodDescription
udp.createSocket()Create a new UDP socket
socket.connect(address, port)Set default send destination
socket.send(data)Send to connected address
socket.write(data, address, port)Send to a specific address without calling connect() first
socket.bind(port)Bind to a local port for receiving
socket.close()Close the socket
socket.on(event, callback)Register an event handler

UDP Events: "connected", "disconnected", "message", "error"


For devices that require encrypted communication (e.g. Philips Hue), use the dtls feature. It provides DTLS-encrypted UDP using a Pre-Shared Key (PSK).

export function Initialize() {
device.addFeature("dtls");
dtls.onConnectionEstablished(() => { device.log("DTLS connected"); });
dtls.onConnectionClosed(() => { device.log("DTLS closed"); });
dtls.onConnectionError(() => { device.log("DTLS error"); });
dtls.createConnection("192.168.1.50", 2100, authIdentity, authKey);
}
export function Render() {
if (dtls.hasEncryptedConnection()) {
dtls.send(RGBData);
}
}
export function Shutdown() {
dtls.CloseConnection();
}

DTLS Methods:

MethodDescription
dtls.createConnection(host, port, identity, key)Open an encrypted connection using a PSK
dtls.send(data, endianness?)Send encrypted data (0 = little-endian, 1 = big-endian)
dtls.hasEncryptedConnection()Returns true if the connection is established
dtls.CloseConnection()Close the connection
dtls.onConnectionEstablished(cb)Callback when connection succeeds
dtls.onConnectionClosed(cb)Callback when connection closes
dtls.onConnectionError(cb)Callback on error