Browse Source
* Initial Node.js serial transport * Minor doc fixes * Add serialport to lockfile * Typo fix * Fix link:pull/784/head
committed by
GitHub
6 changed files with 182 additions and 0 deletions
@ -0,0 +1,28 @@ |
|||||
|
# @meshtastic/transport-node-serial |
||||
|
|
||||
|
[](https://jsr.io/@meshtastic/transport-node-serial) |
||||
|
[](https://github.com/meshtastic/js/actions/workflows/ci.yml) |
||||
|
[](https://cla-assistant.io/meshtastic/meshtastic.js) |
||||
|
[](https://opencollective.com/meshtastic/) |
||||
|
[](https://vercel.com?utm_source=meshtastic&utm_campaign=oss) |
||||
|
|
||||
|
## Overview |
||||
|
|
||||
|
`@meshtastic/transport-noden-node` Provides Serial transport (Node) for Meshtastic |
||||
|
devices. Installation instructions are available at |
||||
|
[JSR](https://jsr.io/@meshtastic/transport-node-serial) |
||||
|
[NPM](https://www.npmjs.com/package/@meshtastic/transport-node-serial) |
||||
|
|
||||
|
## Usage |
||||
|
|
||||
|
```ts |
||||
|
import { MeshDevice } from "@meshtastic/core"; |
||||
|
import { TransportNodeSerial } from "@meshtastic/transport-node-serial"; |
||||
|
|
||||
|
const transport = await TransportNodeSerial.create("/dev/cu.usbserial-0001"); |
||||
|
const device = new MeshDevice(transport); |
||||
|
``` |
||||
|
|
||||
|
## Stats |
||||
|
|
||||
|
 |
||||
@ -0,0 +1 @@ |
|||||
|
export { TransportNodeSerial } from "./src/transport.ts"; |
||||
@ -0,0 +1,39 @@ |
|||||
|
{ |
||||
|
"name": "@meshtastic/transport-node-serial", |
||||
|
"version": "0.0.1", |
||||
|
"description": "NodeJS-specific serial transport layer for Meshtastic web applications.", |
||||
|
"exports": { |
||||
|
".": "./dist/mod.mjs" |
||||
|
}, |
||||
|
"main": "./dist/mod.mjs", |
||||
|
"module": "./dist/mod.mjs", |
||||
|
"types": "./dist/mod.d.mts", |
||||
|
|
||||
|
"license": "GPL-3.0-only", |
||||
|
"tsdown": { |
||||
|
"entry": "mod.ts", |
||||
|
"dts": true, |
||||
|
"format": ["esm"], |
||||
|
"splitting": false, |
||||
|
"clean": true |
||||
|
}, |
||||
|
"files": [ |
||||
|
"package.json", |
||||
|
"README.md", |
||||
|
"LICENSE", |
||||
|
"dist" |
||||
|
], |
||||
|
"scripts": { |
||||
|
"preinstall": "npx only-allow pnpm", |
||||
|
"prepack": "cp ../../LICENSE ./LICENSE", |
||||
|
"clean": "rm -rf dist LICENSE", |
||||
|
"build:npm": "tsdown", |
||||
|
"publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public", |
||||
|
"prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr", |
||||
|
"publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check" |
||||
|
}, |
||||
|
"dependencies": { |
||||
|
"@meshtastic/core": "workspace:*", |
||||
|
"serialport": "^13.0.0" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,87 @@ |
|||||
|
import { Readable, Writable } from "node:stream"; |
||||
|
import type { Types } from "@meshtastic/core"; |
||||
|
import { Utils } from "@meshtastic/core"; |
||||
|
import { SerialPort } from "serialport"; |
||||
|
|
||||
|
export class TransportNodeSerial implements Types.Transport { |
||||
|
private readonly _toDevice: WritableStream<Uint8Array>; |
||||
|
private readonly _fromDevice: ReadableStream<Types.DeviceOutput>; |
||||
|
private port: SerialPort | undefined; |
||||
|
|
||||
|
/** |
||||
|
* Creates and connects a new TransportNode instance. |
||||
|
* @param path - Path to the serial device |
||||
|
* @param baudRate - The port number for the TCP connection (defaults to 4403). |
||||
|
* @returns A promise that resolves with a connected TransportNode instance. |
||||
|
*/ |
||||
|
public static create(path: string, baudRate = 115200): Promise<TransportNodeSerial> { |
||||
|
return new Promise((resolve, reject) => { |
||||
|
const port = new SerialPort({ |
||||
|
path, |
||||
|
baudRate, |
||||
|
autoOpen: true, |
||||
|
}); |
||||
|
|
||||
|
const onError = (err: Error) => { |
||||
|
port.close(); |
||||
|
reject(err); |
||||
|
}; |
||||
|
|
||||
|
port.once("error", onError); |
||||
|
port.on("open", () => { |
||||
|
port.removeListener("error", onError); |
||||
|
resolve(new TransportNodeSerial(port)); |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Constructs a new TransportNode. |
||||
|
* @param port - An active Node.js SerialPort connection. |
||||
|
*/ |
||||
|
constructor(port: SerialPort) { |
||||
|
this.port = port; |
||||
|
this.port.on("error", (err) => { |
||||
|
console.error("Serial port connection error:", err); |
||||
|
}); |
||||
|
|
||||
|
const fromDeviceSource = Readable.toWeb( |
||||
|
port, |
||||
|
) as ReadableStream<Uint8Array>; |
||||
|
this._fromDevice = fromDeviceSource.pipeThrough(Utils.fromDeviceStream()); |
||||
|
|
||||
|
// Stream for data going FROM the application TO the Meshtastic device.
|
||||
|
const toDeviceTransform = Utils.toDeviceStream; |
||||
|
this._toDevice = toDeviceTransform.writable; |
||||
|
|
||||
|
// The readable end of the transform is then piped to the Node.js SerialPort connection.
|
||||
|
// A similar assertion is needed here because `Writable.toWeb` also returns
|
||||
|
// a generically typed stream (`WritableStream<any>`).
|
||||
|
toDeviceTransform.readable |
||||
|
.pipeTo(Writable.toWeb(port) as WritableStream<Uint8Array>) |
||||
|
.catch((err) => { |
||||
|
console.error("Error piping data to serial port:", err); |
||||
|
this.port.close(err as Error); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* The WritableStream to send data to the Meshtastic device. |
||||
|
*/ |
||||
|
public get toDevice(): WritableStream<Uint8Array> { |
||||
|
return this._toDevice; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* The ReadableStream to receive data from the Meshtastic device. |
||||
|
*/ |
||||
|
public get fromDevice(): ReadableStream<Types.DeviceOutput> { |
||||
|
return this._fromDevice; |
||||
|
} |
||||
|
|
||||
|
disconnect() { |
||||
|
this.port.close(); |
||||
|
this.port = undefined; |
||||
|
return Promise.resolve(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
{ |
||||
|
"extends": "../../tsconfig.json", |
||||
|
"compilerOptions": { |
||||
|
"module": "ESNext", |
||||
|
"target": "ES2020", |
||||
|
"declaration": true, |
||||
|
"outDir": "./dist", |
||||
|
"moduleResolution": "bundler", |
||||
|
"emitDeclarationOnly": false, |
||||
|
"esModuleInterop": true, |
||||
|
}, |
||||
|
"include": ["src"] |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
Loading…
Reference in new issue