Skip to content

Commit 58d82a0

Browse files
committed
docs: add AT, Modbus RTU, Plantower examples and fix driver-kit stale reference
- Add examples/at-modem-chat — query AT modem identity, signal, registration - Add examples/modbus-read-holding — read holding registers from Modbus RTU slave - Add examples/plantower-read — stream PM readings from Plantower sensor - Update driver-kit README: three flagship → six downstream drivers - Update root README Examples section with all six examples
1 parent d0ff87e commit 58d82a0

18 files changed

Lines changed: 402 additions & 1 deletion

File tree

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@ All drivers consume the published `serialpilot` core toolkit from npm. Each driv
2020

2121
Runnable examples live under [`examples/`](./examples/):
2222

23+
- [`at-modem-chat`](./examples/at-modem-chat/) — query an AT modem for identity, signal, and registration
2324
- [`gps-live-fix`](./examples/gps-live-fix/) — print live NMEA fixes
2425
- [`grbl-jog-cli`](./examples/grbl-jog-cli/) — interactive CNC jog control
2526
- [`esp-flash-blink`](./examples/esp-flash-blink/) — flash a `.bin` to an ESP chip
27+
- [`modbus-read-holding`](./examples/modbus-read-holding/) — read holding registers from a Modbus RTU slave
28+
- [`plantower-read`](./examples/plantower-read/) — stream particulate matter readings from a Plantower PM sensor
2629

2730
Each example includes a small `serialPilotTransport.ts` adapter that wraps `SerialPilot`'s callback-style API in the promise-based `Transport` interface that drivers expect.
2831

examples/at-modem-chat/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# at-modem-chat
2+
3+
Queries an AT-command modem for device identity, signal strength, and network registration, then prints any unsolicited result codes (URCs) that arrive.
4+
5+
```sh
6+
npm install
7+
npm start -- /dev/ttyUSB0
8+
```
9+
10+
Default baud rate is 115200. Adjust in `src/index.ts` if your modem uses a different rate.
11+
12+
## What it shows
13+
14+
- `@serialpilot/driver-at` end-to-end against a real port via `serialpilot`.
15+
- Standard 3GPP helpers: `getIdentity()`, `getImei()`, `getIccid()`, `getSignalStrength()`, `getNetworkRegistration()`.
16+
- `'urc'` event handling for inbound unsolicited result codes.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "@serialpilot-examples/at-modem-chat",
3+
"version": "0.0.0",
4+
"private": true,
5+
"type": "module",
6+
"scripts": {
7+
"start": "tsx src/index.ts"
8+
},
9+
"dependencies": {
10+
"@serialpilot/driver-at": "*",
11+
"@serialpilot/driver-kit": "*",
12+
"serialpilot": "^1.0.1"
13+
},
14+
"devDependencies": {
15+
"@types/node": "25.0.3",
16+
"tsx": "4.20.6"
17+
}
18+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { AtModem } from '@serialpilot/driver-at'
2+
import { serialPilotTransport } from './serialPilotTransport.ts'
3+
4+
const path = process.argv[2]
5+
if (!path) {
6+
console.error('usage: at-modem-chat <port>')
7+
process.exit(1)
8+
}
9+
10+
const transport = serialPilotTransport({ path, baudRate: 115200 })
11+
const modem = new AtModem({ transport })
12+
13+
modem.on('urc', ({ line }) => console.log(`URC: ${line}`))
14+
15+
await modem.open()
16+
17+
console.log('Identity: ', await modem.getIdentity())
18+
console.log('IMEI: ', await modem.getImei())
19+
console.log('ICCID: ', await modem.getIccid())
20+
21+
const signal = await modem.getSignalStrength()
22+
console.log(`Signal: RSSI=${signal.rssi ?? '?'} BER=${signal.ber ?? '?'}`)
23+
24+
const reg = await modem.getNetworkRegistration()
25+
console.log(`Registration: ${reg.status}${reg.lac ? ` LAC=${reg.lac}` : ''}${reg.cellId ? ` Cell=${reg.cellId}` : ''}`)
26+
27+
await modem.close()
28+
console.log('Done.')
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { EventEmitter } from 'node:events'
2+
import { SerialPilot } from 'serialpilot'
3+
import type { Transport } from '@serialpilot/driver-kit'
4+
5+
/**
6+
* Adapt a `SerialPilot` (callback-style API) to the promise-based `Transport`
7+
* interface that `@serialpilot/driver-*` packages expect. Keeps examples readable
8+
* without forcing driver-kit to take a runtime dependency on the core toolkit.
9+
*/
10+
export function serialPilotTransport(opts: { path: string, baudRate: number }): Transport {
11+
const port = new SerialPilot({ path: opts.path, baudRate: opts.baudRate, autoOpen: false })
12+
const emitter = new EventEmitter() as EventEmitter & Transport
13+
14+
const transport: Transport = Object.assign(emitter, {
15+
get isOpen() { return port.isOpen },
16+
open() {
17+
return new Promise<void>((resolve, reject) => {
18+
port.open(err => err ? reject(err) : resolve())
19+
})
20+
},
21+
close() {
22+
return new Promise<void>((resolve, reject) => {
23+
port.close(err => err ? reject(err) : resolve())
24+
})
25+
},
26+
write(data: Uint8Array | string) {
27+
return new Promise<void>((resolve, reject) => {
28+
port.write(data as Buffer | string, err => err ? reject(err) : resolve())
29+
})
30+
},
31+
setSignals(signals: { dtr?: boolean, rts?: boolean }) {
32+
return new Promise<void>((resolve, reject) => {
33+
port.set(signals, err => err ? reject(err) : resolve())
34+
})
35+
},
36+
})
37+
38+
port.on('data', (chunk: Buffer) => emitter.emit('data', chunk))
39+
port.on('error', (err: Error) => emitter.emit('error', err))
40+
port.on('close', () => emitter.emit('close'))
41+
42+
return transport
43+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": "../../tsconfig.json",
3+
"compilerOptions": {
4+
"rootDir": "./src",
5+
"noEmit": true
6+
},
7+
"include": ["src/**/*.ts"]
8+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# modbus-read-holding
2+
3+
Reads holding registers from a Modbus RTU slave device and prints the values.
4+
5+
```sh
6+
npm install
7+
npm start -- /dev/ttyUSB0
8+
```
9+
10+
Default baud rate is 9600 (typical for RS-485 Modbus). Adjust in `src/index.ts` for your bus.
11+
12+
## What it shows
13+
14+
- `@serialpilot/driver-modbus-rtu` end-to-end against a real port via `serialpilot`.
15+
- `readHoldingRegisters()` with typed error handling.
16+
- Slave address and register count configurable in source.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "@serialpilot-examples/modbus-read-holding",
3+
"version": "0.0.0",
4+
"private": true,
5+
"type": "module",
6+
"scripts": {
7+
"start": "tsx src/index.ts"
8+
},
9+
"dependencies": {
10+
"@serialpilot/driver-kit": "*",
11+
"@serialpilot/driver-modbus-rtu": "*",
12+
"serialpilot": "^1.0.1"
13+
},
14+
"devDependencies": {
15+
"@types/node": "25.0.3",
16+
"tsx": "4.20.6"
17+
}
18+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { ModbusRtuMaster } from '@serialpilot/driver-modbus-rtu'
2+
import { serialPilotTransport } from './serialPilotTransport.ts'
3+
4+
const path = process.argv[2]
5+
if (!path) {
6+
console.error('usage: modbus-read-holding <port>')
7+
process.exit(1)
8+
}
9+
10+
const SLAVE = 1
11+
const START_ADDR = 0
12+
const QUANTITY = 10
13+
14+
const transport = serialPilotTransport({ path, baudRate: 9600 })
15+
const modbus = new ModbusRtuMaster({ transport })
16+
17+
await modbus.open()
18+
19+
try {
20+
const regs = await modbus.readHoldingRegisters(SLAVE, START_ADDR, QUANTITY)
21+
console.log(`Slave ${SLAVE} — holding registers ${START_ADDR}${START_ADDR + QUANTITY - 1}:`)
22+
for (let i = 0; i < regs.length; i++) {
23+
console.log(` ${String(START_ADDR + i).padStart(4)}: ${regs[i]}`)
24+
}
25+
} catch (e) {
26+
console.error('Modbus error:', (e as Error).message)
27+
} finally {
28+
await modbus.close()
29+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { EventEmitter } from 'node:events'
2+
import { SerialPilot } from 'serialpilot'
3+
import type { Transport } from '@serialpilot/driver-kit'
4+
5+
/**
6+
* Adapt a `SerialPilot` (callback-style API) to the promise-based `Transport`
7+
* interface that `@serialpilot/driver-*` packages expect. Keeps examples readable
8+
* without forcing driver-kit to take a runtime dependency on the core toolkit.
9+
*/
10+
export function serialPilotTransport(opts: { path: string, baudRate: number }): Transport {
11+
const port = new SerialPilot({ path: opts.path, baudRate: opts.baudRate, autoOpen: false })
12+
const emitter = new EventEmitter() as EventEmitter & Transport
13+
14+
const transport: Transport = Object.assign(emitter, {
15+
get isOpen() { return port.isOpen },
16+
open() {
17+
return new Promise<void>((resolve, reject) => {
18+
port.open(err => err ? reject(err) : resolve())
19+
})
20+
},
21+
close() {
22+
return new Promise<void>((resolve, reject) => {
23+
port.close(err => err ? reject(err) : resolve())
24+
})
25+
},
26+
write(data: Uint8Array | string) {
27+
return new Promise<void>((resolve, reject) => {
28+
port.write(data as Buffer | string, err => err ? reject(err) : resolve())
29+
})
30+
},
31+
setSignals(signals: { dtr?: boolean, rts?: boolean }) {
32+
return new Promise<void>((resolve, reject) => {
33+
port.set(signals, err => err ? reject(err) : resolve())
34+
})
35+
},
36+
})
37+
38+
port.on('data', (chunk: Buffer) => emitter.emit('data', chunk))
39+
port.on('error', (err: Error) => emitter.emit('error', err))
40+
port.on('close', () => emitter.emit('close'))
41+
42+
return transport
43+
}

0 commit comments

Comments
 (0)