jmri-client 4.2.0-beta.1 → 4.2.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -0
- package/docs/API.md +39 -4
- package/docs/EXAMPLES.md +42 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,6 +19,7 @@ WebSocket client for [JMRI](http://jmri.sourceforge.net/) with real-time updates
|
|
|
19
19
|
- ✅ **Heartbeat monitoring** - Automatic ping/pong keepalive
|
|
20
20
|
- ✅ **TypeScript** - Full type definitions included
|
|
21
21
|
- ✅ **Dual module support** - ESM and CommonJS
|
|
22
|
+
- ✅ **Multi-connection** - Target specific hardware connections by prefix when multiple are configured
|
|
22
23
|
- ✅ **Extensible** - Subclass `JmriClient` to add support for additional JMRI object types
|
|
23
24
|
|
|
24
25
|
## Installation
|
|
@@ -106,6 +107,20 @@ client.on('reconnecting', (attempt, delay) => {
|
|
|
106
107
|
});
|
|
107
108
|
```
|
|
108
109
|
|
|
110
|
+
### Multi-Connection Support
|
|
111
|
+
|
|
112
|
+
When JMRI has multiple hardware connections configured, use `getSystemConnections()` to discover their prefixes and pass them to power and throttle commands:
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
const connections = await client.getSystemConnections();
|
|
116
|
+
// [{ name: 'LocoNet', prefix: 'L' }, { name: 'DCC++', prefix: 'D' }]
|
|
117
|
+
|
|
118
|
+
await client.powerOn('L'); // LocoNet only
|
|
119
|
+
const throttle = await client.acquireThrottle({ address: 3, prefix: 'L' });
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
When no prefix is supplied the command routes to JMRI's default connection manager, which is the correct behaviour for single-connection layouts.
|
|
123
|
+
|
|
109
124
|
### Extending JmriClient
|
|
110
125
|
|
|
111
126
|
`JmriClient` exposes its `wsClient` as `protected`, so you can subclass it to add support for JMRI object types not yet built in (e.g., sensors, lights, routes, blocks):
|
package/docs/API.md
CHANGED
|
@@ -65,6 +65,9 @@ client.on('heartbeat:timeout', () => { });
|
|
|
65
65
|
// Get current power state
|
|
66
66
|
const state: PowerState = await client.getPower();
|
|
67
67
|
|
|
68
|
+
// Get power state for a specific hardware connection (see System Connections)
|
|
69
|
+
const state: PowerState = await client.getPower('L'); // LocoNet prefix
|
|
70
|
+
|
|
68
71
|
// PowerState enum values (from JMRI JSON protocol):
|
|
69
72
|
// PowerState.UNKNOWN = 0 (state cannot be determined)
|
|
70
73
|
// PowerState.ON = 2 (power is on)
|
|
@@ -83,10 +86,15 @@ switch (state) {
|
|
|
83
86
|
break;
|
|
84
87
|
}
|
|
85
88
|
|
|
86
|
-
// Set power
|
|
89
|
+
// Set power (all connections, or a specific one)
|
|
87
90
|
await client.setPower(PowerState.ON);
|
|
88
|
-
await client.
|
|
89
|
-
|
|
91
|
+
await client.setPower(PowerState.ON, 'L'); // LocoNet only
|
|
92
|
+
|
|
93
|
+
// Convenience methods — all accept an optional prefix
|
|
94
|
+
await client.powerOn(); // All connections
|
|
95
|
+
await client.powerOn('L'); // LocoNet only
|
|
96
|
+
await client.powerOff(); // All connections
|
|
97
|
+
await client.powerOff('D'); // DCC++ only
|
|
90
98
|
|
|
91
99
|
// Listen for power changes (including UNKNOWN states)
|
|
92
100
|
client.on('power:changed', (state: PowerState) => {
|
|
@@ -96,6 +104,29 @@ client.on('power:changed', (state: PowerState) => {
|
|
|
96
104
|
});
|
|
97
105
|
```
|
|
98
106
|
|
|
107
|
+
## System Connections
|
|
108
|
+
|
|
109
|
+
Discover the hardware connections JMRI has configured and their short prefix strings. Use these prefixes to target power and throttle commands at a specific connection when multiple are active.
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
// List all available system connections
|
|
113
|
+
const connections: SystemConnectionData[] = await client.getSystemConnections();
|
|
114
|
+
// [
|
|
115
|
+
// { name: 'LocoNet', prefix: 'L', userName: 'LocoNet' },
|
|
116
|
+
// { name: 'DCC++', prefix: 'D' }
|
|
117
|
+
// ]
|
|
118
|
+
|
|
119
|
+
// Use a prefix to target a specific connection
|
|
120
|
+
const [loconet] = connections.filter(c => c.name === 'LocoNet');
|
|
121
|
+
await client.powerOn(loconet.prefix);
|
|
122
|
+
|
|
123
|
+
// Acquire a throttle on a specific connection
|
|
124
|
+
const throttleId = await client.acquireThrottle({
|
|
125
|
+
address: 3,
|
|
126
|
+
prefix: loconet.prefix
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
99
130
|
## Roster Management
|
|
100
131
|
|
|
101
132
|
```typescript
|
|
@@ -150,6 +181,9 @@ client.on('light:changed', (name: string, state: LightState) => {
|
|
|
150
181
|
// Acquire throttle
|
|
151
182
|
const throttleId = await client.acquireThrottle({ address: 3 });
|
|
152
183
|
|
|
184
|
+
// Acquire throttle on a specific hardware connection
|
|
185
|
+
const throttleId = await client.acquireThrottle({ address: 3, prefix: 'L' });
|
|
186
|
+
|
|
153
187
|
// Control speed (0.0 to 1.0)
|
|
154
188
|
await client.setThrottleSpeed(throttleId, 0.0); // Stopped
|
|
155
189
|
await client.setThrottleSpeed(throttleId, 0.5); // Half speed
|
|
@@ -237,6 +271,7 @@ import {
|
|
|
237
271
|
TurnoutData,
|
|
238
272
|
ThrottleState,
|
|
239
273
|
ThrottleFunctionKey,
|
|
240
|
-
ConnectionState
|
|
274
|
+
ConnectionState,
|
|
275
|
+
SystemConnectionData
|
|
241
276
|
} from 'jmri-client';
|
|
242
277
|
```
|
package/docs/EXAMPLES.md
CHANGED
|
@@ -283,6 +283,48 @@ async function runLayout() {
|
|
|
283
283
|
runLayout();
|
|
284
284
|
```
|
|
285
285
|
|
|
286
|
+
## Multi-Connection / Hardware Prefix
|
|
287
|
+
|
|
288
|
+
When JMRI is configured with more than one hardware connection (e.g. both LocoNet and DCC++), use `getSystemConnections()` to discover the available prefixes, then pass them to power and throttle commands to target a specific connection.
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
import { JmriClient } from 'jmri-client';
|
|
292
|
+
|
|
293
|
+
const client = new JmriClient({ host: 'jmri.local' });
|
|
294
|
+
|
|
295
|
+
client.on('connected', async () => {
|
|
296
|
+
// Discover what hardware connections JMRI has configured
|
|
297
|
+
const connections = await client.getSystemConnections();
|
|
298
|
+
console.log('Available connections:');
|
|
299
|
+
for (const conn of connections) {
|
|
300
|
+
console.log(` ${conn.name} (prefix: "${conn.prefix}")`);
|
|
301
|
+
}
|
|
302
|
+
// Available connections:
|
|
303
|
+
// LocoNet (prefix: "L")
|
|
304
|
+
// DCC++ (prefix: "D")
|
|
305
|
+
|
|
306
|
+
// Power on via LocoNet only
|
|
307
|
+
await client.powerOn('L');
|
|
308
|
+
|
|
309
|
+
// Acquire a throttle on LocoNet
|
|
310
|
+
const throttle = await client.acquireThrottle({ address: 3, prefix: 'L' });
|
|
311
|
+
await client.setThrottleDirection(throttle, true);
|
|
312
|
+
await client.setThrottleSpeed(throttle, 0.3);
|
|
313
|
+
|
|
314
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
315
|
+
|
|
316
|
+
await client.setThrottleSpeed(throttle, 0);
|
|
317
|
+
await client.releaseThrottle(throttle);
|
|
318
|
+
|
|
319
|
+
// Power off via LocoNet only
|
|
320
|
+
await client.powerOff('L');
|
|
321
|
+
|
|
322
|
+
await client.disconnect();
|
|
323
|
+
});
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
Single-connection layouts work exactly as before — just omit the prefix and JMRI routes to the default connection.
|
|
327
|
+
|
|
286
328
|
## CommonJS Usage
|
|
287
329
|
|
|
288
330
|
```javascript
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jmri-client",
|
|
3
|
-
"version": "4.2.0-beta.
|
|
3
|
+
"version": "4.2.0-beta.2",
|
|
4
4
|
"description": "WebSocket client for JMRI with real-time updates and throttle control - works in both Node.js and browsers",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"module": "./dist/esm/index.js",
|