Skip to content

s00d/tauri-plugin-serialplugin

Repository files navigation

npm version Crates.io GitHub issues GitHub stars Donate

Tauri Plugin - SerialPort

A comprehensive plugin for Tauri applications to communicate with serial ports. This plugin provides a complete API for reading from and writing to serial devices, with support for various configuration options and control signals.

Table of Contents

Installation

Prerequisites

  • Rust version 1.70 or higher
  • Tauri 2.0 or higher
  • Node.js and npm/yarn/pnpm

Installation Methods

Using crates.io and npm (Recommended)

# Install the Rust dependency
cargo add tauri-plugin-serialplugin
# Install JavaScript bindings
npm add tauri-plugin-serialplugin
# or
yarn add tauri-plugin-serialplugin
# or
pnpm add tauri-plugin-serialplugin

Basic Usage

  1. Register the Plugin
// src-tauri/src/main.rs
fn main() {
    tauri::Builder::default()
        .plugin(tauri_plugin_serialplugin::init())
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
  1. Configure Permissions
// src-tauri/capabilities/default.json
{
  "$schema": "../gen/schemas/desktop-schema.json",
  "identifier": "default",
  "description": "Capability for the main window",
  "windows": ["main"],
  "permissions": [
    "core:default",
    "serialplugin:default"
  ]
}

Permission Descriptions

Permission Description
serialplugin:allow-available-ports Allows listing of available serial ports
serialplugin:deny-available-ports Denies listing of available serial ports
serialplugin:allow-cancel-read Allows canceling of read operations
serialplugin:deny-cancel-read Denies canceling of read operations
serialplugin:allow-close Allows closing of serial ports
serialplugin:deny-close Denies closing of serial ports
serialplugin:allow-close-all Allows closing of all open serial ports
serialplugin:deny-close-all Denies closing of all open serial ports
serialplugin:allow-force-close Allows forcefully closing of serial ports
serialplugin:deny-force-close Denies forcefully closing of serial ports
serialplugin:allow-open Allows opening of serial ports
serialplugin:deny-open Denies opening of serial ports
serialplugin:allow-read Allows reading data from serial ports
serialplugin:deny-read Denies reading data from serial ports
serialplugin:allow-write Allows writing data to serial ports
serialplugin:deny-write Denies writing data to serial ports
serialplugin:allow-write-binary Allows writing binary data to serial ports
serialplugin:deny-write-binary Denies writing binary data to serial ports
serialplugin:allow-available-ports-direct Enables the available_ports_direct command without any pre-configured scope
serialplugin:deny-available-ports-direct Denies the available_ports_direct command without any pre-configured scope
serialplugin:allow-set-baud-rate Allows changing the baud rate of serial ports
serialplugin:deny-set-baud-rate Denies changing the baud rate of serial ports
serialplugin:allow-set-data-bits Allows changing the data bits configuration
serialplugin:deny-set-data-bits Denies changing the data bits configuration
serialplugin:allow-set-flow-control Allows changing the flow control mode
serialplugin:deny-set-flow-control Denies changing the flow control mode
serialplugin:allow-set-parity Allows changing the parity checking mode
serialplugin:deny-set-parity Denies changing the parity checking mode
serialplugin:allow-set-stop-bits Allows changing the stop bits configuration
serialplugin:deny-set-stop-bits Denies changing the stop bits configuration
serialplugin:allow-set-timeout Allows changing the timeout duration
serialplugin:deny-set-timeout Denies changing the timeout duration
serialplugin:allow-write-rts Allows setting the RTS (Request To Send) control signal
serialplugin:deny-write-rts Denies setting the RTS control signal
serialplugin:allow-write-dtr Allows setting the DTR (Data Terminal Ready) control signal
serialplugin:deny-write-dtr Denies setting the DTR control signal
serialplugin:allow-read-cts Allows reading the CTS (Clear To Send) control signal state
serialplugin:deny-read-cts Denies reading the CTS control signal state
serialplugin:allow-read-dsr Allows reading the DSR (Data Set Ready) control signal state
serialplugin:deny-read-dsr Denies reading the DSR control signal state
serialplugin:allow-read-ri Allows reading the RI (Ring Indicator) control signal state
serialplugin:deny-read-ri Denies reading the RI control signal state
serialplugin:allow-read-cd Allows reading the CD (Carrier Detect) control signal state
serialplugin:deny-read-cd Denies reading the CD control signal state
serialplugin:allow-bytes-to-read Allows checking the number of bytes available to read
serialplugin:deny-bytes-to-read Denies checking the number of bytes available to read
serialplugin:allow-bytes-to-write Allows checking the number of bytes waiting to be written
serialplugin:deny-bytes-to-write Denies checking the number of bytes waiting to be written
serialplugin:allow-clear-buffer Allows clearing input/output buffers
serialplugin:deny-clear-buffer Denies clearing input/output buffers
serialplugin:allow-set-break Allows starting break signal transmission
serialplugin:deny-set-break Denies starting break signal transmission
serialplugin:allow-clear-break Allows stopping break signal transmission
serialplugin:deny-clear-break Denies stopping break signal transmission
serialplugin:allow-start-listening Allows starting automatic port monitoring and data listening
serialplugin:deny-start-listening Denies starting automatic port monitoring and data listening
serialplugin:allow-stop-listening Allows stopping automatic port monitoring and data listening
serialplugin:deny-stop-listening Denies stopping automatic port monitoring and data listening

Allow all

"permissions": [
    "core:default",
    "serialplugin:default",
    "serialplugin:allow-bytes-to-read",
    "serialplugin:allow-bytes-to-write",
    "serialplugin:allow-clear-buffer",
    "serialplugin:allow-read-clear-to-send",
    "serialplugin:allow-read-data-set-ready",
    "serialplugin:allow-read-ring-indicator",
    "serialplugin:allow-read-carrier-detect",
    "serialplugin:allow-set-baud-rate",
    "serialplugin:allow-available-ports",
    "serialplugin:allow-cancel-read",
    "serialplugin:allow-close",
    "serialplugin:allow-close-all",
    "serialplugin:allow-force-close",
    "serialplugin:allow-open",
    "serialplugin:allow-read",
    "serialplugin:allow-write",
    "serialplugin:allow-write-binary",
    "serialplugin:allow-available-ports-direct",
    "serialplugin:allow-set-data-bits",
    "serialplugin:allow-set-flow-control",
    "serialplugin:allow-set-parity",
    "serialplugin:allow-set-stop-bits",
    "serialplugin:allow-set-timeout",
    "serialplugin:allow-write-dtr",
    "serialplugin:allow-read-cts",
    "serialplugin:allow-read-dsr",
    "serialplugin:allow-read-ri",
    "serialplugin:allow-read-cd",
    "serialplugin:allow-set-break",
    "serialplugin:allow-clear-break",
    "serialplugin:allow-start-listening",
    "serialplugin:allow-stop-listening",
    "serialplugin:allow-write-request-to-send",
    "serialplugin:allow-write-data-terminal-ready"
  ]
  1. Basic Example
import { SerialPort } from "tauri-plugin-serialplugin";

// List available ports
const ports = await SerialPort.available_ports();
console.log('Available ports:', ports);

// Open a port
const port = new SerialPort({ 
  path: "COM1", 
  baudRate: 9600 
});

await port.open();

// Write data
await port.write("Hello, Serial Port!");

// Start port listening
await serialport.startListening();
// Read data with event listener
await port.listen((data) => {
  console.log('Received:', data);
});

// Stop port listening
await serialport.stopListening();

// Close port
await port.close();

API Reference

Port Discovery

class SerialPort {
    /**
     * Lists all available serial ports on the system
     * @returns {Promise<{[key: string]: PortInfo}>} Map of port names to port information
     * @example
     * const ports = await SerialPort.available_ports();
     * console.log(ports);
     * // Output: { 
     * //   "COM1": { type: "USB", manufacturer: "FTDI", ... },
     * //   "COM2": { type: "PCI", ... }
     * // }
     */
    static async available_ports(): Promise<{ [key: string]: PortInfo }>;

    /**
     * Lists ports using platform-specific commands for enhanced detection
     * @returns {Promise<{[key: string]: PortInfo}>} Map of port names to port information
     * @example
     * const ports = await SerialPort.available_ports_direct();
     */
    static async available_ports_direct(): Promise<{ [key: string]: PortInfo }>;
}

Connection Management

class SerialPort {
    /**
     * Opens the serial port with specified configuration
     * @returns {Promise<void>}
     * @throws {Error} If port is already open or invalid configuration
     * @example
     * const port = new SerialPort({ path: "COM1", baudRate: 9600 });
     * await port.open();
     */
    async open(): Promise<void>;

    /**
     * Closes the serial port connection
     * @returns {Promise<void>}
     * @throws {Error} If port is not open
     * @example
     * await port.close();
     */
    async close(): Promise<void>;
    
     /**
      * Starts listening for data on the serial port
      * The port will continuously monitor for incoming data and emit events
      * @returns {Promise<void>} A promise that resolves when listening starts
      * @throws {Error} If starting listener fails or port is not open
      * @example
      * const port = new SerialPort({ path: '/dev/ttyUSB0' });
      * await port.startListening();
      * // Listen for data events
      * port.listen((data) => {
      *   console.log('listen', data)
      *   receivedData += data;
      *   updatePortStatus();
      * });
      */
      async startListening(): Promise<void>;
      
      /**
         * Stops listening for data on the serial port
         * Cleans up event listeners and monitoring threads
         * @returns {Promise<void>} A promise that resolves when listening stops
         * @throws {Error} If stopping listener fails or port is not open
         * @example
         * await port.stopListening();
       * */
      async stopListening(): Promise<void> {

    /**
     * Forces a serial port to close regardless of its state
     * @param {string} path Port path to force close
     * @returns {Promise<void>}
     * @example
     * await SerialPort.forceClose("COM1");
     */
    static async forceClose(path: string): Promise<void>;

    /**
     * Closes all open serial port connections
     * @returns {Promise<void>}
     * @example
     * await SerialPort.closeAll();
     */
    static async closeAll(): Promise<void>;
}

Data Transfer

class SerialPort {
    /**
     * Writes string data to the serial port
     * @param {string} data Data to write
     * @returns {Promise<number>} Number of bytes written
     * @throws {Error} If write fails or port is not open
     * @example
     * const bytesWritten = await port.write("Hello");
     */
    async write(data: string): Promise<number>;

   /**
    * @description Reads data from the serial port
    * @param {ReadOptions} [options] Read options
    * @returns {Promise<void>} A promise that resolves when data is read
    */
   async read(options?: ReadOptions): Promise<string>;

    /**
     * Writes binary data to the serial port
     * @param {Uint8Array | number[]} data Binary data to write
     * @returns {Promise<number>} Number of bytes written
     * @throws {Error} If write fails or port is not open
     * @example
     * const data = new Uint8Array([0x01, 0x02, 0x03]);
     * const bytesWritten = await port.writeBinary(data);
     */
    async writeBinary(data: Uint8Array | number[]): Promise<number>;

    /**
     * Sets up a listener for incoming data
     * @param {(data: string | Uint8Array) => void} callback Function to handle received data
     * @param {boolean} [decode=true] Whether to decode data as string (true) or return raw bytes (false)
     * @returns {Promise<void>}
     * @example
     * await port.listen((data) => {
     *   console.log('Received:', data);
     * });
     */
    async listen(callback: (data: string | Uint8Array) => void, decode?: boolean): Promise<void>;
}

Port Configuration

class SerialPort {
    /**
     * Sets the baud rate
     * @param {number} baudRate Speed in bits per second
     * @returns {Promise<void>}
     * @example
     * await port.setBaudRate(115200);
     */
    async setBaudRate(baudRate: number): Promise<void>;

    /**
     * Sets the number of data bits
     * @param {DataBits} dataBits Number of bits per character (5-8)
     * @returns {Promise<void>}
     * @example
     * await port.setDataBits(DataBits.Eight);
     */
    async setDataBits(dataBits: DataBits): Promise<void>;

    /**
     * Sets the flow control mode
     * @param {FlowControl} flowControl Flow control setting
     * @returns {Promise<void>}
     * @example
     * await port.setFlowControl(FlowControl.Hardware);
     */
    async setFlowControl(flowControl: FlowControl): Promise<void>;

    /**
     * Sets the parity checking mode
     * @param {Parity} parity Parity checking mode
     * @returns {Promise<void>}
     * @example
     * await port.setParity(Parity.None);
     */
    async setParity(parity: Parity): Promise<void>;

    /**
     * Sets the number of stop bits
     * @param {StopBits} stopBits Number of stop bits
     * @returns {Promise<void>}
     * @example
     * await port.setStopBits(StopBits.One);
     */
    async setStopBits(stopBits: StopBits): Promise<void>;
}

Control Signals

class SerialPort {
    /**
     * Sets the RTS (Request to Send) signal
     * @param {boolean} level Signal level (true = high, false = low)
     * @returns {Promise<void>}
     * @example
     * await port.writeRequestToSend(true);
     */
    async writeRequestToSend(level: boolean): Promise<void>;

    /**
     * Sets the DTR (Data Terminal Ready) signal
     * @param {boolean} level Signal level (true = high, false = low)
     * @returns {Promise<void>}
     * @example
     * await port.writeDataTerminalReady(true);
     */
    async writeDataTerminalReady(level: boolean): Promise<void>;

    /**
     * Reads the CTS (Clear to Send) signal state
     * @returns {Promise<boolean>} Signal state
     * @example
     * const cts = await port.readClearToSend();
     */
    async readClearToSend(): Promise<boolean>;

    /**
     * Reads the DSR (Data Set Ready) signal state
     * @returns {Promise<boolean>} Signal state
     * @example
     * const dsr = await port.readDataSetReady();
     */
    async readDataSetReady(): Promise<boolean>;

    /**
     * Reads the RI (Ring Indicator) signal state
     * @returns {Promise<boolean>} Signal state
     * @example
     * const ri = await port.readRingIndicator();
     */
    async readRingIndicator(): Promise<boolean>;

    /**
     * Reads the CD (Carrier Detect) signal state
     * @returns {Promise<boolean>} Signal state
     * @example
     * const cd = await port.readCarrierDetect();
     */
    async readCarrierDetect(): Promise<boolean>;
}

Buffer Management

class SerialPort {
    /**
     * Gets number of bytes available to read
     * @returns {Promise<number>} Number of bytes in read buffer
     * @example
     * const available = await port.bytesToRead();
     */
    async bytesToRead(): Promise<number>;

    /**
     * Gets number of bytes waiting to be written
     * @returns {Promise<number>} Number of bytes in write buffer
     * @example
     * const pending = await port.bytesToWrite();
     */
    async bytesToWrite(): Promise<number>;

    /**
     * Clears the specified buffer
     * @param {ClearBuffer} buffer Buffer to clear
     * @returns {Promise<void>}
     * @example
     * await port.clearBuffer(ClearBuffer.Input);
     */
    async clearBuffer(buffer: ClearBuffer): Promise<void>;
}

Common Use Cases

Reading Sensor Data

const port = new SerialPort({ 
  path: "COM1", 
  baudRate: 9600 
});

await port.open();
await port.listen((data) => {
  const sensorValue = parseFloat(data);
  console.log('Sensor reading:', sensorValue);
});

Binary Protocol Communication

const port = new SerialPort({ 
  path: "COM1", 
  baudRate: 115200 
});

await port.open();

// Send command
const command = new Uint8Array([0x02, 0x01, 0x03]);
await port.writeBinary(command);

// Read response
await port.listen((data) => {
  const response = new Uint8Array(data);
  console.log('Response:', response);
}, false);

Modbus Communication

const port = new SerialPort({ 
  path: "COM1", 
  baudRate: 9600,
  dataBits: DataBits.Eight,
  stopBits: StopBits.One,
  parity: Parity.None
});

await port.open();

function createModbusRequest(address: number, length: number): Uint8Array {
  return new Uint8Array([0x01, 0x03, address >> 8, address & 0xFF, length >> 8, length & 0xFF]);
}

// Send Modbus request
const request = createModbusRequest(0x1000, 10);
await port.writeBinary(request);

Android Setup

To use this plugin on Android, you need to add the JitPack repository to your project's build.gradle.kts file located at /src-tauri/gen/android/build.gradle.kts. Below is an example of how to configure it:

buildscript {
    repositories {
        // ...
        maven { url = uri("https://jitpack.io") }
    }
    // ...
}

allprojects {
    repositories {
        // ...
        maven { url = uri("https://jitpack.io") }
    }
}

Contributing

We welcome pull requests! Please ensure you read our Contributing Guide before submitting a pull request.

Partners

Support for this plugin is provided by our generous partners. For a complete list, please visit our website and our Open Collective.

License

This code is dual-licensed under MIT or Apache-2.0, where applicable, © 2019-2023 Tauri Programme within The Commons Conservancy.