jmri-client 4.1.0 → 4.2.0-beta.1
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/dist/browser/jmri-client.js +71 -17
- package/dist/cjs/client.js +33 -8
- package/dist/cjs/managers/index.js +1 -0
- package/dist/cjs/managers/power-manager.js +14 -8
- package/dist/cjs/managers/system-connections-manager.js +28 -0
- package/dist/cjs/managers/throttle-manager.js +2 -1
- package/dist/esm/client.js +33 -8
- package/dist/esm/managers/index.js +1 -0
- package/dist/esm/managers/power-manager.js +14 -8
- package/dist/esm/managers/system-connections-manager.js +24 -0
- package/dist/esm/managers/throttle-manager.js +2 -1
- package/dist/types/client.d.ts +24 -5
- package/dist/types/managers/index.d.ts +1 -0
- package/dist/types/managers/power-manager.d.ts +9 -4
- package/dist/types/managers/system-connections-manager.d.ts +15 -0
- package/dist/types/types/jmri-messages.d.ts +18 -1
- package/dist/types/types/throttle.d.ts +6 -0
- package/docs/API.md +46 -1
- package/docs/EXAMPLES.md +31 -0
- package/docs/MOCK_MODE.md +16 -0
- package/package.json +1 -1
|
@@ -1481,10 +1481,12 @@ var PowerManager = class extends import_index.default {
|
|
|
1481
1481
|
}
|
|
1482
1482
|
/**
|
|
1483
1483
|
* Get current track power state
|
|
1484
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
1484
1485
|
*/
|
|
1485
|
-
async getPower() {
|
|
1486
|
+
async getPower(prefix) {
|
|
1486
1487
|
const message = {
|
|
1487
|
-
type: "power"
|
|
1488
|
+
type: "power",
|
|
1489
|
+
...prefix !== void 0 && { data: { state: 0 /* UNKNOWN */, prefix } }
|
|
1488
1490
|
};
|
|
1489
1491
|
const response = await this.client.request(message);
|
|
1490
1492
|
if (response.data?.state !== void 0) {
|
|
@@ -1494,12 +1496,14 @@ var PowerManager = class extends import_index.default {
|
|
|
1494
1496
|
}
|
|
1495
1497
|
/**
|
|
1496
1498
|
* Set track power state
|
|
1499
|
+
* @param state - The desired power state
|
|
1500
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
1497
1501
|
*/
|
|
1498
|
-
async setPower(state) {
|
|
1502
|
+
async setPower(state, prefix) {
|
|
1499
1503
|
const message = {
|
|
1500
1504
|
type: "power",
|
|
1501
1505
|
method: "post",
|
|
1502
|
-
data: { state }
|
|
1506
|
+
data: { state, ...prefix !== void 0 && { prefix } }
|
|
1503
1507
|
};
|
|
1504
1508
|
await this.client.request(message);
|
|
1505
1509
|
const oldState = this.currentState;
|
|
@@ -1510,15 +1514,17 @@ var PowerManager = class extends import_index.default {
|
|
|
1510
1514
|
}
|
|
1511
1515
|
/**
|
|
1512
1516
|
* Turn track power on
|
|
1517
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
1513
1518
|
*/
|
|
1514
|
-
async powerOn() {
|
|
1515
|
-
await this.setPower(2 /* ON
|
|
1519
|
+
async powerOn(prefix) {
|
|
1520
|
+
await this.setPower(2 /* ON */, prefix);
|
|
1516
1521
|
}
|
|
1517
1522
|
/**
|
|
1518
1523
|
* Turn track power off
|
|
1524
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
1519
1525
|
*/
|
|
1520
|
-
async powerOff() {
|
|
1521
|
-
await this.setPower(4 /* OFF
|
|
1526
|
+
async powerOff(prefix) {
|
|
1527
|
+
await this.setPower(4 /* OFF */, prefix);
|
|
1522
1528
|
}
|
|
1523
1529
|
/**
|
|
1524
1530
|
* Get cached power state (no network request)
|
|
@@ -1672,7 +1678,8 @@ var ThrottleManager = class extends import_index.default {
|
|
|
1672
1678
|
type: "throttle",
|
|
1673
1679
|
data: {
|
|
1674
1680
|
name: throttleName,
|
|
1675
|
-
address: options.address
|
|
1681
|
+
address: options.address,
|
|
1682
|
+
...options.prefix !== void 0 && { prefix: options.prefix }
|
|
1676
1683
|
}
|
|
1677
1684
|
};
|
|
1678
1685
|
const response = await this.client.request(message);
|
|
@@ -2051,6 +2058,29 @@ var LightManager = class extends import_index.default {
|
|
|
2051
2058
|
}
|
|
2052
2059
|
};
|
|
2053
2060
|
|
|
2061
|
+
// src/managers/system-connections-manager.ts
|
|
2062
|
+
var SystemConnectionsManager = class {
|
|
2063
|
+
constructor(client) {
|
|
2064
|
+
this.client = client;
|
|
2065
|
+
}
|
|
2066
|
+
/**
|
|
2067
|
+
* List all available JMRI system connections and their prefixes.
|
|
2068
|
+
* Use the returned prefix values with power and throttle commands to
|
|
2069
|
+
* target a specific hardware connection when multiple are configured.
|
|
2070
|
+
*/
|
|
2071
|
+
async getSystemConnections() {
|
|
2072
|
+
const message = {
|
|
2073
|
+
type: "systemConnections",
|
|
2074
|
+
method: "list"
|
|
2075
|
+
};
|
|
2076
|
+
const response = await this.client.request(message);
|
|
2077
|
+
if (!response.data) {
|
|
2078
|
+
return [];
|
|
2079
|
+
}
|
|
2080
|
+
return Array.isArray(response.data) ? response.data : [response.data];
|
|
2081
|
+
}
|
|
2082
|
+
};
|
|
2083
|
+
|
|
2054
2084
|
// src/types/client-options.ts
|
|
2055
2085
|
var DEFAULT_CLIENT_OPTIONS = {
|
|
2056
2086
|
host: "localhost",
|
|
@@ -2128,6 +2158,7 @@ var JmriClient = class extends import_index.default {
|
|
|
2128
2158
|
this.throttleManager = new ThrottleManager(this.wsClient);
|
|
2129
2159
|
this.turnoutManager = new TurnoutManager(this.wsClient);
|
|
2130
2160
|
this.lightManager = new LightManager(this.wsClient);
|
|
2161
|
+
this.systemConnectionsManager = new SystemConnectionsManager(this.wsClient);
|
|
2131
2162
|
this.wsClient.on("connected", () => this.emit("connected"));
|
|
2132
2163
|
this.wsClient.on("disconnected", (reason) => this.emit("disconnected", reason));
|
|
2133
2164
|
this.wsClient.on(
|
|
@@ -2212,27 +2243,50 @@ var JmriClient = class extends import_index.default {
|
|
|
2212
2243
|
// ============================================================================
|
|
2213
2244
|
/**
|
|
2214
2245
|
* Get current track power state
|
|
2246
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
2215
2247
|
*/
|
|
2216
|
-
async getPower() {
|
|
2217
|
-
return this.powerManager.getPower();
|
|
2248
|
+
async getPower(prefix) {
|
|
2249
|
+
return this.powerManager.getPower(prefix);
|
|
2218
2250
|
}
|
|
2219
2251
|
/**
|
|
2220
2252
|
* Set track power state
|
|
2253
|
+
* @param state - The desired power state
|
|
2254
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
2221
2255
|
*/
|
|
2222
|
-
async setPower(state) {
|
|
2223
|
-
return this.powerManager.setPower(state);
|
|
2256
|
+
async setPower(state, prefix) {
|
|
2257
|
+
return this.powerManager.setPower(state, prefix);
|
|
2224
2258
|
}
|
|
2225
2259
|
/**
|
|
2226
2260
|
* Turn track power on
|
|
2261
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
2227
2262
|
*/
|
|
2228
|
-
async powerOn() {
|
|
2229
|
-
return this.powerManager.powerOn();
|
|
2263
|
+
async powerOn(prefix) {
|
|
2264
|
+
return this.powerManager.powerOn(prefix);
|
|
2230
2265
|
}
|
|
2231
2266
|
/**
|
|
2232
2267
|
* Turn track power off
|
|
2268
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
2269
|
+
*/
|
|
2270
|
+
async powerOff(prefix) {
|
|
2271
|
+
return this.powerManager.powerOff(prefix);
|
|
2272
|
+
}
|
|
2273
|
+
// ============================================================================
|
|
2274
|
+
// System Connections
|
|
2275
|
+
// ============================================================================
|
|
2276
|
+
/**
|
|
2277
|
+
* List all available JMRI system connections and their prefixes.
|
|
2278
|
+
* Use the returned prefix values with power and throttle commands to
|
|
2279
|
+
* target a specific hardware connection when multiple are configured.
|
|
2280
|
+
*
|
|
2281
|
+
* @example
|
|
2282
|
+
* ```typescript
|
|
2283
|
+
* const connections = await client.getSystemConnections();
|
|
2284
|
+
* // [{ name: 'LocoNet', prefix: 'L' }, { name: 'DCC++', prefix: 'D' }]
|
|
2285
|
+
* await client.powerOn('L'); // power on via LocoNet only
|
|
2286
|
+
* ```
|
|
2233
2287
|
*/
|
|
2234
|
-
async
|
|
2235
|
-
return this.
|
|
2288
|
+
async getSystemConnections() {
|
|
2289
|
+
return this.systemConnectionsManager.getSystemConnections();
|
|
2236
2290
|
}
|
|
2237
2291
|
// ============================================================================
|
|
2238
2292
|
// Roster Management
|
package/dist/cjs/client.js
CHANGED
|
@@ -11,6 +11,7 @@ const roster_manager_js_1 = require("./managers/roster-manager.js");
|
|
|
11
11
|
const throttle_manager_js_1 = require("./managers/throttle-manager.js");
|
|
12
12
|
const turnout_manager_js_1 = require("./managers/turnout-manager.js");
|
|
13
13
|
const light_manager_js_1 = require("./managers/light-manager.js");
|
|
14
|
+
const system_connections_manager_js_1 = require("./managers/system-connections-manager.js");
|
|
14
15
|
const client_options_js_1 = require("./types/client-options.js");
|
|
15
16
|
/**
|
|
16
17
|
* JMRI WebSocket Client
|
|
@@ -45,6 +46,7 @@ class JmriClient extends eventemitter3_1.EventEmitter {
|
|
|
45
46
|
this.throttleManager = new throttle_manager_js_1.ThrottleManager(this.wsClient);
|
|
46
47
|
this.turnoutManager = new turnout_manager_js_1.TurnoutManager(this.wsClient);
|
|
47
48
|
this.lightManager = new light_manager_js_1.LightManager(this.wsClient);
|
|
49
|
+
this.systemConnectionsManager = new system_connections_manager_js_1.SystemConnectionsManager(this.wsClient);
|
|
48
50
|
// Forward events from WebSocket client
|
|
49
51
|
this.wsClient.on('connected', () => this.emit('connected'));
|
|
50
52
|
this.wsClient.on('disconnected', (reason) => this.emit('disconnected', reason));
|
|
@@ -104,27 +106,50 @@ class JmriClient extends eventemitter3_1.EventEmitter {
|
|
|
104
106
|
// ============================================================================
|
|
105
107
|
/**
|
|
106
108
|
* Get current track power state
|
|
109
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
107
110
|
*/
|
|
108
|
-
async getPower() {
|
|
109
|
-
return this.powerManager.getPower();
|
|
111
|
+
async getPower(prefix) {
|
|
112
|
+
return this.powerManager.getPower(prefix);
|
|
110
113
|
}
|
|
111
114
|
/**
|
|
112
115
|
* Set track power state
|
|
116
|
+
* @param state - The desired power state
|
|
117
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
113
118
|
*/
|
|
114
|
-
async setPower(state) {
|
|
115
|
-
return this.powerManager.setPower(state);
|
|
119
|
+
async setPower(state, prefix) {
|
|
120
|
+
return this.powerManager.setPower(state, prefix);
|
|
116
121
|
}
|
|
117
122
|
/**
|
|
118
123
|
* Turn track power on
|
|
124
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
119
125
|
*/
|
|
120
|
-
async powerOn() {
|
|
121
|
-
return this.powerManager.powerOn();
|
|
126
|
+
async powerOn(prefix) {
|
|
127
|
+
return this.powerManager.powerOn(prefix);
|
|
122
128
|
}
|
|
123
129
|
/**
|
|
124
130
|
* Turn track power off
|
|
131
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
125
132
|
*/
|
|
126
|
-
async powerOff() {
|
|
127
|
-
return this.powerManager.powerOff();
|
|
133
|
+
async powerOff(prefix) {
|
|
134
|
+
return this.powerManager.powerOff(prefix);
|
|
135
|
+
}
|
|
136
|
+
// ============================================================================
|
|
137
|
+
// System Connections
|
|
138
|
+
// ============================================================================
|
|
139
|
+
/**
|
|
140
|
+
* List all available JMRI system connections and their prefixes.
|
|
141
|
+
* Use the returned prefix values with power and throttle commands to
|
|
142
|
+
* target a specific hardware connection when multiple are configured.
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```typescript
|
|
146
|
+
* const connections = await client.getSystemConnections();
|
|
147
|
+
* // [{ name: 'LocoNet', prefix: 'L' }, { name: 'DCC++', prefix: 'D' }]
|
|
148
|
+
* await client.powerOn('L'); // power on via LocoNet only
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
async getSystemConnections() {
|
|
152
|
+
return this.systemConnectionsManager.getSystemConnections();
|
|
128
153
|
}
|
|
129
154
|
// ============================================================================
|
|
130
155
|
// Roster Management
|
|
@@ -22,3 +22,4 @@ __exportStar(require("./roster-manager.js"), exports);
|
|
|
22
22
|
__exportStar(require("./throttle-manager.js"), exports);
|
|
23
23
|
__exportStar(require("./turnout-manager.js"), exports);
|
|
24
24
|
__exportStar(require("./light-manager.js"), exports);
|
|
25
|
+
__exportStar(require("./system-connections-manager.js"), exports);
|
|
@@ -23,10 +23,12 @@ class PowerManager extends eventemitter3_1.EventEmitter {
|
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
25
|
* Get current track power state
|
|
26
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
26
27
|
*/
|
|
27
|
-
async getPower() {
|
|
28
|
+
async getPower(prefix) {
|
|
28
29
|
const message = {
|
|
29
|
-
type: 'power'
|
|
30
|
+
type: 'power',
|
|
31
|
+
...(prefix !== undefined && { data: { state: jmri_messages_js_1.PowerState.UNKNOWN, prefix } })
|
|
30
32
|
};
|
|
31
33
|
const response = await this.client.request(message);
|
|
32
34
|
if (response.data?.state !== undefined) {
|
|
@@ -36,12 +38,14 @@ class PowerManager extends eventemitter3_1.EventEmitter {
|
|
|
36
38
|
}
|
|
37
39
|
/**
|
|
38
40
|
* Set track power state
|
|
41
|
+
* @param state - The desired power state
|
|
42
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
39
43
|
*/
|
|
40
|
-
async setPower(state) {
|
|
44
|
+
async setPower(state, prefix) {
|
|
41
45
|
const message = {
|
|
42
46
|
type: 'power',
|
|
43
47
|
method: 'post',
|
|
44
|
-
data: { state }
|
|
48
|
+
data: { state, ...(prefix !== undefined && { prefix }) }
|
|
45
49
|
};
|
|
46
50
|
await this.client.request(message);
|
|
47
51
|
const oldState = this.currentState;
|
|
@@ -52,15 +56,17 @@ class PowerManager extends eventemitter3_1.EventEmitter {
|
|
|
52
56
|
}
|
|
53
57
|
/**
|
|
54
58
|
* Turn track power on
|
|
59
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
55
60
|
*/
|
|
56
|
-
async powerOn() {
|
|
57
|
-
await this.setPower(jmri_messages_js_1.PowerState.ON);
|
|
61
|
+
async powerOn(prefix) {
|
|
62
|
+
await this.setPower(jmri_messages_js_1.PowerState.ON, prefix);
|
|
58
63
|
}
|
|
59
64
|
/**
|
|
60
65
|
* Turn track power off
|
|
66
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
61
67
|
*/
|
|
62
|
-
async powerOff() {
|
|
63
|
-
await this.setPower(jmri_messages_js_1.PowerState.OFF);
|
|
68
|
+
async powerOff(prefix) {
|
|
69
|
+
await this.setPower(jmri_messages_js_1.PowerState.OFF, prefix);
|
|
64
70
|
}
|
|
65
71
|
/**
|
|
66
72
|
* Get cached power state (no network request)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* System connections manager — discovers available JMRI hardware connection prefixes
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SystemConnectionsManager = void 0;
|
|
7
|
+
class SystemConnectionsManager {
|
|
8
|
+
constructor(client) {
|
|
9
|
+
this.client = client;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* List all available JMRI system connections and their prefixes.
|
|
13
|
+
* Use the returned prefix values with power and throttle commands to
|
|
14
|
+
* target a specific hardware connection when multiple are configured.
|
|
15
|
+
*/
|
|
16
|
+
async getSystemConnections() {
|
|
17
|
+
const message = {
|
|
18
|
+
type: 'systemConnections',
|
|
19
|
+
method: 'list'
|
|
20
|
+
};
|
|
21
|
+
const response = await this.client.request(message);
|
|
22
|
+
if (!response.data) {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
return Array.isArray(response.data) ? response.data : [response.data];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.SystemConnectionsManager = SystemConnectionsManager;
|
|
@@ -37,7 +37,8 @@ class ThrottleManager extends eventemitter3_1.EventEmitter {
|
|
|
37
37
|
type: 'throttle',
|
|
38
38
|
data: {
|
|
39
39
|
name: throttleName,
|
|
40
|
-
address: options.address
|
|
40
|
+
address: options.address,
|
|
41
|
+
...(options.prefix !== undefined && { prefix: options.prefix })
|
|
41
42
|
}
|
|
42
43
|
};
|
|
43
44
|
const response = await this.client.request(message);
|
package/dist/esm/client.js
CHANGED
|
@@ -8,6 +8,7 @@ import { RosterManager } from './managers/roster-manager.js';
|
|
|
8
8
|
import { ThrottleManager } from './managers/throttle-manager.js';
|
|
9
9
|
import { TurnoutManager } from './managers/turnout-manager.js';
|
|
10
10
|
import { LightManager } from './managers/light-manager.js';
|
|
11
|
+
import { SystemConnectionsManager } from './managers/system-connections-manager.js';
|
|
11
12
|
import { mergeOptions } from './types/client-options.js';
|
|
12
13
|
/**
|
|
13
14
|
* JMRI WebSocket Client
|
|
@@ -42,6 +43,7 @@ export class JmriClient extends EventEmitter {
|
|
|
42
43
|
this.throttleManager = new ThrottleManager(this.wsClient);
|
|
43
44
|
this.turnoutManager = new TurnoutManager(this.wsClient);
|
|
44
45
|
this.lightManager = new LightManager(this.wsClient);
|
|
46
|
+
this.systemConnectionsManager = new SystemConnectionsManager(this.wsClient);
|
|
45
47
|
// Forward events from WebSocket client
|
|
46
48
|
this.wsClient.on('connected', () => this.emit('connected'));
|
|
47
49
|
this.wsClient.on('disconnected', (reason) => this.emit('disconnected', reason));
|
|
@@ -101,27 +103,50 @@ export class JmriClient extends EventEmitter {
|
|
|
101
103
|
// ============================================================================
|
|
102
104
|
/**
|
|
103
105
|
* Get current track power state
|
|
106
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
104
107
|
*/
|
|
105
|
-
async getPower() {
|
|
106
|
-
return this.powerManager.getPower();
|
|
108
|
+
async getPower(prefix) {
|
|
109
|
+
return this.powerManager.getPower(prefix);
|
|
107
110
|
}
|
|
108
111
|
/**
|
|
109
112
|
* Set track power state
|
|
113
|
+
* @param state - The desired power state
|
|
114
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
110
115
|
*/
|
|
111
|
-
async setPower(state) {
|
|
112
|
-
return this.powerManager.setPower(state);
|
|
116
|
+
async setPower(state, prefix) {
|
|
117
|
+
return this.powerManager.setPower(state, prefix);
|
|
113
118
|
}
|
|
114
119
|
/**
|
|
115
120
|
* Turn track power on
|
|
121
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
116
122
|
*/
|
|
117
|
-
async powerOn() {
|
|
118
|
-
return this.powerManager.powerOn();
|
|
123
|
+
async powerOn(prefix) {
|
|
124
|
+
return this.powerManager.powerOn(prefix);
|
|
119
125
|
}
|
|
120
126
|
/**
|
|
121
127
|
* Turn track power off
|
|
128
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
122
129
|
*/
|
|
123
|
-
async powerOff() {
|
|
124
|
-
return this.powerManager.powerOff();
|
|
130
|
+
async powerOff(prefix) {
|
|
131
|
+
return this.powerManager.powerOff(prefix);
|
|
132
|
+
}
|
|
133
|
+
// ============================================================================
|
|
134
|
+
// System Connections
|
|
135
|
+
// ============================================================================
|
|
136
|
+
/**
|
|
137
|
+
* List all available JMRI system connections and their prefixes.
|
|
138
|
+
* Use the returned prefix values with power and throttle commands to
|
|
139
|
+
* target a specific hardware connection when multiple are configured.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```typescript
|
|
143
|
+
* const connections = await client.getSystemConnections();
|
|
144
|
+
* // [{ name: 'LocoNet', prefix: 'L' }, { name: 'DCC++', prefix: 'D' }]
|
|
145
|
+
* await client.powerOn('L'); // power on via LocoNet only
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
async getSystemConnections() {
|
|
149
|
+
return this.systemConnectionsManager.getSystemConnections();
|
|
125
150
|
}
|
|
126
151
|
// ============================================================================
|
|
127
152
|
// Roster Management
|
|
@@ -20,10 +20,12 @@ export class PowerManager extends EventEmitter {
|
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
22
|
* Get current track power state
|
|
23
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
23
24
|
*/
|
|
24
|
-
async getPower() {
|
|
25
|
+
async getPower(prefix) {
|
|
25
26
|
const message = {
|
|
26
|
-
type: 'power'
|
|
27
|
+
type: 'power',
|
|
28
|
+
...(prefix !== undefined && { data: { state: PowerState.UNKNOWN, prefix } })
|
|
27
29
|
};
|
|
28
30
|
const response = await this.client.request(message);
|
|
29
31
|
if (response.data?.state !== undefined) {
|
|
@@ -33,12 +35,14 @@ export class PowerManager extends EventEmitter {
|
|
|
33
35
|
}
|
|
34
36
|
/**
|
|
35
37
|
* Set track power state
|
|
38
|
+
* @param state - The desired power state
|
|
39
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
36
40
|
*/
|
|
37
|
-
async setPower(state) {
|
|
41
|
+
async setPower(state, prefix) {
|
|
38
42
|
const message = {
|
|
39
43
|
type: 'power',
|
|
40
44
|
method: 'post',
|
|
41
|
-
data: { state }
|
|
45
|
+
data: { state, ...(prefix !== undefined && { prefix }) }
|
|
42
46
|
};
|
|
43
47
|
await this.client.request(message);
|
|
44
48
|
const oldState = this.currentState;
|
|
@@ -49,15 +53,17 @@ export class PowerManager extends EventEmitter {
|
|
|
49
53
|
}
|
|
50
54
|
/**
|
|
51
55
|
* Turn track power on
|
|
56
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
52
57
|
*/
|
|
53
|
-
async powerOn() {
|
|
54
|
-
await this.setPower(PowerState.ON);
|
|
58
|
+
async powerOn(prefix) {
|
|
59
|
+
await this.setPower(PowerState.ON, prefix);
|
|
55
60
|
}
|
|
56
61
|
/**
|
|
57
62
|
* Turn track power off
|
|
63
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
58
64
|
*/
|
|
59
|
-
async powerOff() {
|
|
60
|
-
await this.setPower(PowerState.OFF);
|
|
65
|
+
async powerOff(prefix) {
|
|
66
|
+
await this.setPower(PowerState.OFF, prefix);
|
|
61
67
|
}
|
|
62
68
|
/**
|
|
63
69
|
* Get cached power state (no network request)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* System connections manager — discovers available JMRI hardware connection prefixes
|
|
3
|
+
*/
|
|
4
|
+
export class SystemConnectionsManager {
|
|
5
|
+
constructor(client) {
|
|
6
|
+
this.client = client;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* List all available JMRI system connections and their prefixes.
|
|
10
|
+
* Use the returned prefix values with power and throttle commands to
|
|
11
|
+
* target a specific hardware connection when multiple are configured.
|
|
12
|
+
*/
|
|
13
|
+
async getSystemConnections() {
|
|
14
|
+
const message = {
|
|
15
|
+
type: 'systemConnections',
|
|
16
|
+
method: 'list'
|
|
17
|
+
};
|
|
18
|
+
const response = await this.client.request(message);
|
|
19
|
+
if (!response.data) {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
return Array.isArray(response.data) ? response.data : [response.data];
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -34,7 +34,8 @@ export class ThrottleManager extends EventEmitter {
|
|
|
34
34
|
type: 'throttle',
|
|
35
35
|
data: {
|
|
36
36
|
name: throttleName,
|
|
37
|
-
address: options.address
|
|
37
|
+
address: options.address,
|
|
38
|
+
...(options.prefix !== undefined && { prefix: options.prefix })
|
|
38
39
|
}
|
|
39
40
|
};
|
|
40
41
|
const response = await this.client.request(message);
|
package/dist/types/client.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { EventEmitter } from 'eventemitter3';
|
|
5
5
|
import { WebSocketClient } from './core/websocket-client.js';
|
|
6
6
|
import { PartialClientOptions } from './types/client-options.js';
|
|
7
|
-
import { PowerState, RosterEntryWrapper, TurnoutState, TurnoutData, LightState, LightData } from './types/jmri-messages.js';
|
|
7
|
+
import { PowerState, RosterEntryWrapper, TurnoutState, TurnoutData, LightState, LightData, SystemConnectionData } from './types/jmri-messages.js';
|
|
8
8
|
import { ConnectionState } from './types/events.js';
|
|
9
9
|
import { ThrottleAcquireOptions, ThrottleFunctionKey, ThrottleState } from './types/throttle.js';
|
|
10
10
|
/**
|
|
@@ -19,6 +19,7 @@ export declare class JmriClient extends EventEmitter {
|
|
|
19
19
|
private throttleManager;
|
|
20
20
|
private turnoutManager;
|
|
21
21
|
private lightManager;
|
|
22
|
+
private systemConnectionsManager;
|
|
22
23
|
/**
|
|
23
24
|
* Create a new JMRI client
|
|
24
25
|
*
|
|
@@ -55,20 +56,38 @@ export declare class JmriClient extends EventEmitter {
|
|
|
55
56
|
isConnected(): boolean;
|
|
56
57
|
/**
|
|
57
58
|
* Get current track power state
|
|
59
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
58
60
|
*/
|
|
59
|
-
getPower(): Promise<PowerState>;
|
|
61
|
+
getPower(prefix?: string): Promise<PowerState>;
|
|
60
62
|
/**
|
|
61
63
|
* Set track power state
|
|
64
|
+
* @param state - The desired power state
|
|
65
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
62
66
|
*/
|
|
63
|
-
setPower(state: PowerState): Promise<void>;
|
|
67
|
+
setPower(state: PowerState, prefix?: string): Promise<void>;
|
|
64
68
|
/**
|
|
65
69
|
* Turn track power on
|
|
70
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
66
71
|
*/
|
|
67
|
-
powerOn(): Promise<void>;
|
|
72
|
+
powerOn(prefix?: string): Promise<void>;
|
|
68
73
|
/**
|
|
69
74
|
* Turn track power off
|
|
75
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
70
76
|
*/
|
|
71
|
-
powerOff(): Promise<void>;
|
|
77
|
+
powerOff(prefix?: string): Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* List all available JMRI system connections and their prefixes.
|
|
80
|
+
* Use the returned prefix values with power and throttle commands to
|
|
81
|
+
* target a specific hardware connection when multiple are configured.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```typescript
|
|
85
|
+
* const connections = await client.getSystemConnections();
|
|
86
|
+
* // [{ name: 'LocoNet', prefix: 'L' }, { name: 'DCC++', prefix: 'D' }]
|
|
87
|
+
* await client.powerOn('L'); // power on via LocoNet only
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
getSystemConnections(): Promise<SystemConnectionData[]>;
|
|
72
91
|
/**
|
|
73
92
|
* Get all roster entries
|
|
74
93
|
*/
|
|
@@ -13,20 +13,25 @@ export declare class PowerManager extends EventEmitter {
|
|
|
13
13
|
constructor(client: WebSocketClient);
|
|
14
14
|
/**
|
|
15
15
|
* Get current track power state
|
|
16
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
16
17
|
*/
|
|
17
|
-
getPower(): Promise<PowerState>;
|
|
18
|
+
getPower(prefix?: string): Promise<PowerState>;
|
|
18
19
|
/**
|
|
19
20
|
* Set track power state
|
|
21
|
+
* @param state - The desired power state
|
|
22
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
20
23
|
*/
|
|
21
|
-
setPower(state: PowerState): Promise<void>;
|
|
24
|
+
setPower(state: PowerState, prefix?: string): Promise<void>;
|
|
22
25
|
/**
|
|
23
26
|
* Turn track power on
|
|
27
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
24
28
|
*/
|
|
25
|
-
powerOn(): Promise<void>;
|
|
29
|
+
powerOn(prefix?: string): Promise<void>;
|
|
26
30
|
/**
|
|
27
31
|
* Turn track power off
|
|
32
|
+
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
28
33
|
*/
|
|
29
|
-
powerOff(): Promise<void>;
|
|
34
|
+
powerOff(prefix?: string): Promise<void>;
|
|
30
35
|
/**
|
|
31
36
|
* Get cached power state (no network request)
|
|
32
37
|
*/
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* System connections manager — discovers available JMRI hardware connection prefixes
|
|
3
|
+
*/
|
|
4
|
+
import { WebSocketClient } from '../core/websocket-client.js';
|
|
5
|
+
import { SystemConnectionData } from '../types/jmri-messages.js';
|
|
6
|
+
export declare class SystemConnectionsManager {
|
|
7
|
+
private client;
|
|
8
|
+
constructor(client: WebSocketClient);
|
|
9
|
+
/**
|
|
10
|
+
* List all available JMRI system connections and their prefixes.
|
|
11
|
+
* Use the returned prefix values with power and throttle commands to
|
|
12
|
+
* target a specific hardware connection when multiple are configured.
|
|
13
|
+
*/
|
|
14
|
+
getSystemConnections(): Promise<SystemConnectionData[]>;
|
|
15
|
+
}
|
|
@@ -33,6 +33,7 @@ export declare function powerStateToString(state: PowerState): string;
|
|
|
33
33
|
*/
|
|
34
34
|
export interface PowerData {
|
|
35
35
|
state: PowerState;
|
|
36
|
+
prefix?: string;
|
|
36
37
|
}
|
|
37
38
|
/**
|
|
38
39
|
* Power message
|
|
@@ -41,6 +42,21 @@ export interface PowerMessage extends JmriMessage {
|
|
|
41
42
|
type: 'power';
|
|
42
43
|
data?: PowerData;
|
|
43
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* System connection data (from JMRI systemConnections list)
|
|
47
|
+
*/
|
|
48
|
+
export interface SystemConnectionData {
|
|
49
|
+
name: string;
|
|
50
|
+
prefix: string;
|
|
51
|
+
userName?: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* System connections message
|
|
55
|
+
*/
|
|
56
|
+
export interface SystemConnectionsMessage extends JmriMessage {
|
|
57
|
+
type: 'systemConnections';
|
|
58
|
+
data?: SystemConnectionData | SystemConnectionData[];
|
|
59
|
+
}
|
|
44
60
|
/**
|
|
45
61
|
* Throttle data structure
|
|
46
62
|
*/
|
|
@@ -51,6 +67,7 @@ export interface ThrottleData {
|
|
|
51
67
|
forward?: boolean;
|
|
52
68
|
release?: null;
|
|
53
69
|
status?: string;
|
|
70
|
+
prefix?: string;
|
|
54
71
|
F0?: boolean;
|
|
55
72
|
F1?: boolean;
|
|
56
73
|
F2?: boolean;
|
|
@@ -263,4 +280,4 @@ export interface ErrorMessage extends JmriMessage {
|
|
|
263
280
|
/**
|
|
264
281
|
* Union type of all possible JMRI messages
|
|
265
282
|
*/
|
|
266
|
-
export type AnyJmriMessage = PowerMessage | ThrottleMessage | RosterMessage | TurnoutMessage | LightMessage | PingMessage | PongMessage | HelloMessage | GoodbyeMessage | ErrorMessage;
|
|
283
|
+
export type AnyJmriMessage = PowerMessage | ThrottleMessage | RosterMessage | TurnoutMessage | LightMessage | SystemConnectionsMessage | PingMessage | PongMessage | HelloMessage | GoodbyeMessage | ErrorMessage;
|
|
@@ -13,6 +13,12 @@ export interface ThrottleAcquireOptions {
|
|
|
13
13
|
* Whether this is a long address (default: true for addresses > 127)
|
|
14
14
|
*/
|
|
15
15
|
isLongAddress?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* JMRI connection prefix to target a specific hardware connection.
|
|
18
|
+
* When omitted, routes to the default connection manager.
|
|
19
|
+
* Use getSystemConnections() to discover available prefixes.
|
|
20
|
+
*/
|
|
21
|
+
prefix?: string;
|
|
16
22
|
}
|
|
17
23
|
/**
|
|
18
24
|
* Throttle function key (F0-F28)
|
package/docs/API.md
CHANGED
|
@@ -42,6 +42,12 @@ client.on('error', (error: Error) => { });
|
|
|
42
42
|
// Power events
|
|
43
43
|
client.on('power:changed', (state: PowerState) => { });
|
|
44
44
|
|
|
45
|
+
// Turnout events
|
|
46
|
+
client.on('turnout:changed', (name: string, state: TurnoutState) => { });
|
|
47
|
+
|
|
48
|
+
// Light events
|
|
49
|
+
client.on('light:changed', (name: string, state: LightState) => { });
|
|
50
|
+
|
|
45
51
|
// Throttle events
|
|
46
52
|
client.on('throttle:acquired', (throttleId: string) => { });
|
|
47
53
|
client.on('throttle:updated', (throttleId: string, data: any) => { });
|
|
@@ -106,6 +112,38 @@ const entry = await client.getRosterEntryByAddress(3);
|
|
|
106
112
|
const results = await client.searchRoster('steam');
|
|
107
113
|
```
|
|
108
114
|
|
|
115
|
+
## Light Control
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
// Get current light state
|
|
119
|
+
const state: LightState = await client.getLight('IL1');
|
|
120
|
+
|
|
121
|
+
// LightState enum values (from JMRI JSON protocol):
|
|
122
|
+
// LightState.UNKNOWN = 0 (state cannot be determined)
|
|
123
|
+
// LightState.ON = 2 (light is on)
|
|
124
|
+
// LightState.OFF = 4 (light is off)
|
|
125
|
+
|
|
126
|
+
// Set light state
|
|
127
|
+
await client.setLight('IL1', LightState.ON);
|
|
128
|
+
await client.turnOnLight('IL1'); // Convenience method
|
|
129
|
+
await client.turnOffLight('IL1'); // Convenience method
|
|
130
|
+
|
|
131
|
+
// List all lights
|
|
132
|
+
const lights: LightData[] = await client.listLights();
|
|
133
|
+
for (const light of lights) {
|
|
134
|
+
console.log(`${light.userName}: ${light.state === LightState.ON ? 'ON' : 'OFF'}`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Cached state (no network request)
|
|
138
|
+
const cachedState = client.getLightState('IL1');
|
|
139
|
+
const allCached = client.getCachedLights();
|
|
140
|
+
|
|
141
|
+
// Listen for light changes
|
|
142
|
+
client.on('light:changed', (name: string, state: LightState) => {
|
|
143
|
+
console.log(`Light ${name} changed to ${state === LightState.ON ? 'ON' : 'OFF'}`);
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
109
147
|
## Throttle Control
|
|
110
148
|
|
|
111
149
|
```typescript
|
|
@@ -165,12 +203,15 @@ const state = client.getConnectionState();
|
|
|
165
203
|
## Utility Functions
|
|
166
204
|
|
|
167
205
|
```typescript
|
|
168
|
-
import { powerStateToString, isThrottleFunctionKey, isValidSpeed } from 'jmri-client';
|
|
206
|
+
import { powerStateToString, lightStateToString, isThrottleFunctionKey, isValidSpeed } from 'jmri-client';
|
|
169
207
|
|
|
170
208
|
// Convert PowerState enum to readable string
|
|
171
209
|
const stateStr = powerStateToString(PowerState.ON); // 'ON'
|
|
172
210
|
const stateStr2 = powerStateToString(PowerState.UNKNOWN); // 'UNKNOWN'
|
|
173
211
|
|
|
212
|
+
// Convert LightState enum to readable string
|
|
213
|
+
const lightStr = lightStateToString(LightState.ON); // 'ON'
|
|
214
|
+
|
|
174
215
|
// Validate throttle function key
|
|
175
216
|
isThrottleFunctionKey('F0'); // true
|
|
176
217
|
isThrottleFunctionKey('F99'); // false
|
|
@@ -189,7 +230,11 @@ import {
|
|
|
189
230
|
JmriClient,
|
|
190
231
|
JmriClientOptions,
|
|
191
232
|
PowerState,
|
|
233
|
+
LightState,
|
|
234
|
+
LightData,
|
|
192
235
|
RosterEntry,
|
|
236
|
+
TurnoutState,
|
|
237
|
+
TurnoutData,
|
|
193
238
|
ThrottleState,
|
|
194
239
|
ThrottleFunctionKey,
|
|
195
240
|
ConnectionState
|
package/docs/EXAMPLES.md
CHANGED
|
@@ -113,6 +113,37 @@ client.on('connected', async () => {
|
|
|
113
113
|
});
|
|
114
114
|
```
|
|
115
115
|
|
|
116
|
+
## Light Control
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import { JmriClient, LightState } from 'jmri-client';
|
|
120
|
+
|
|
121
|
+
const client = new JmriClient({ host: 'jmri.local' });
|
|
122
|
+
|
|
123
|
+
client.on('connected', async () => {
|
|
124
|
+
// List all lights
|
|
125
|
+
const lights = await client.listLights();
|
|
126
|
+
console.log(`Found ${lights.length} lights`);
|
|
127
|
+
|
|
128
|
+
for (const light of lights) {
|
|
129
|
+
console.log(` ${light.userName ?? light.name}: ${light.state === LightState.ON ? 'ON' : 'OFF'}`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Turn a light on
|
|
133
|
+
await client.turnOnLight('IL1');
|
|
134
|
+
console.log('Light IL1 turned ON');
|
|
135
|
+
|
|
136
|
+
// Turn it off again
|
|
137
|
+
await client.turnOffLight('IL1');
|
|
138
|
+
console.log('Light IL1 turned OFF');
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Monitor light changes in real-time
|
|
142
|
+
client.on('light:changed', (name, state) => {
|
|
143
|
+
console.log(`Light ${name} is now ${state === LightState.ON ? 'ON' : 'OFF'}`);
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
116
147
|
## Roster Search
|
|
117
148
|
|
|
118
149
|
```typescript
|
package/docs/MOCK_MODE.md
CHANGED
|
@@ -72,6 +72,18 @@ Three sample locomotives:
|
|
|
72
72
|
|
|
73
73
|
Each includes realistic function key mappings (F0-F4).
|
|
74
74
|
|
|
75
|
+
### Lights
|
|
76
|
+
Three sample lights:
|
|
77
|
+
- **IL1** - Yard Light (OFF)
|
|
78
|
+
- **IL2** - Platform Light (OFF)
|
|
79
|
+
- **IL3** - Signal Lamp (ON)
|
|
80
|
+
|
|
81
|
+
### Turnouts
|
|
82
|
+
Three sample turnouts:
|
|
83
|
+
- **LT1** - Main Diverge (CLOSED)
|
|
84
|
+
- **LT2** - Yard Lead (CLOSED)
|
|
85
|
+
- **LT3** - Siding Entry (THROWN)
|
|
86
|
+
|
|
75
87
|
### Throttle Responses
|
|
76
88
|
Supports all throttle operations:
|
|
77
89
|
- Acquire/release
|
|
@@ -152,6 +164,8 @@ const response = await mockManager.getMockResponse({
|
|
|
152
164
|
The mock system maintains state for realistic behavior:
|
|
153
165
|
|
|
154
166
|
- **Power state** - Remembers if power is ON or OFF
|
|
167
|
+
- **Light states** - Tracks ON/OFF state per light
|
|
168
|
+
- **Turnout states** - Tracks CLOSED/THROWN state per turnout
|
|
155
169
|
- **Throttles** - Tracks acquired throttles and their states
|
|
156
170
|
- **Speed/Direction** - Maintains current speed and direction per throttle
|
|
157
171
|
- **Functions** - Tracks function key states (F0-F28)
|
|
@@ -196,6 +210,8 @@ Mock mode implements the full JMRI client API. All methods work identically:
|
|
|
196
210
|
- ✅ `connect()` / `disconnect()`
|
|
197
211
|
- ✅ `getPower()` / `powerOn()` / `powerOff()`
|
|
198
212
|
- ✅ `getRoster()`
|
|
213
|
+
- ✅ `getLight()` / `setLight()` / `turnOnLight()` / `turnOffLight()` / `listLights()`
|
|
214
|
+
- ✅ `getTurnout()` / `setTurnout()` / `throwTurnout()` / `closeTurnout()` / `listTurnouts()`
|
|
199
215
|
- ✅ `acquireThrottle()` / `releaseThrottle()`
|
|
200
216
|
- ✅ `setThrottleSpeed()`
|
|
201
217
|
- ✅ `setThrottleDirection()`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jmri-client",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.0-beta.1",
|
|
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",
|