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 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.powerOn(); // Convenience method
89
- await client.powerOff(); // Convenience method
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.1",
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",