jmri-client 4.2.0-beta.2 → 5.1.0
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 +3 -1
- package/dist/browser/jmri-client.js +88 -28
- package/dist/cjs/index.js +2442 -31
- package/dist/esm/index.js +2393 -17
- package/dist/types/client.d.ts +9 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/managers/roster-manager.d.ts +9 -1
- package/dist/types/mocks/mock-data.d.ts +30 -6
- package/dist/types/mocks/mock-response-manager.d.ts +7 -2
- package/dist/types/types/jmri-messages.d.ts +22 -0
- package/docs/API.md +8 -0
- package/docs/BROWSER.md +4 -4
- package/docs/MIGRATION.md +30 -1
- package/docs/MOCK_MODE.md +15 -9
- package/package.json +17 -18
- package/dist/cjs/client.js +0 -366
- package/dist/cjs/core/connection-state-manager.js +0 -84
- package/dist/cjs/core/heartbeat-manager.js +0 -79
- package/dist/cjs/core/index.js +0 -25
- package/dist/cjs/core/message-queue.js +0 -59
- package/dist/cjs/core/reconnection-manager.js +0 -97
- package/dist/cjs/core/websocket-adapter.js +0 -135
- package/dist/cjs/core/websocket-client.js +0 -388
- package/dist/cjs/managers/index.js +0 -25
- package/dist/cjs/managers/light-manager.js +0 -111
- package/dist/cjs/managers/power-manager.js +0 -90
- package/dist/cjs/managers/roster-manager.js +0 -118
- package/dist/cjs/managers/system-connections-manager.js +0 -28
- package/dist/cjs/managers/throttle-manager.js +0 -233
- package/dist/cjs/managers/turnout-manager.js +0 -111
- package/dist/cjs/mocks/index.js +0 -12
- package/dist/cjs/mocks/mock-data.js +0 -237
- package/dist/cjs/mocks/mock-response-manager.js +0 -290
- package/dist/cjs/types/client-options.js +0 -66
- package/dist/cjs/types/events.js +0 -16
- package/dist/cjs/types/index.js +0 -23
- package/dist/cjs/types/jmri-messages.js +0 -95
- package/dist/cjs/types/throttle.js +0 -19
- package/dist/cjs/utils/exponential-backoff.js +0 -40
- package/dist/cjs/utils/index.js +0 -21
- package/dist/cjs/utils/message-id.js +0 -40
- package/dist/esm/client.js +0 -362
- package/dist/esm/core/connection-state-manager.js +0 -80
- package/dist/esm/core/heartbeat-manager.js +0 -75
- package/dist/esm/core/index.js +0 -9
- package/dist/esm/core/message-queue.js +0 -55
- package/dist/esm/core/reconnection-manager.js +0 -93
- package/dist/esm/core/websocket-adapter.js +0 -98
- package/dist/esm/core/websocket-client.js +0 -384
- package/dist/esm/managers/index.js +0 -9
- package/dist/esm/managers/light-manager.js +0 -107
- package/dist/esm/managers/power-manager.js +0 -86
- package/dist/esm/managers/roster-manager.js +0 -114
- package/dist/esm/managers/system-connections-manager.js +0 -24
- package/dist/esm/managers/throttle-manager.js +0 -229
- package/dist/esm/managers/turnout-manager.js +0 -107
- package/dist/esm/mocks/index.js +0 -6
- package/dist/esm/mocks/mock-data.js +0 -234
- package/dist/esm/mocks/mock-response-manager.js +0 -286
- package/dist/esm/types/client-options.js +0 -62
- package/dist/esm/types/events.js +0 -13
- package/dist/esm/types/index.js +0 -7
- package/dist/esm/types/jmri-messages.js +0 -89
- package/dist/esm/types/throttle.js +0 -15
- package/dist/esm/utils/exponential-backoff.js +0 -36
- package/dist/esm/utils/index.js +0 -5
- package/dist/esm/utils/message-id.js +0 -36
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* JMRI WebSocket Protocol Message Types
|
|
4
|
-
* Based on JMRI JSON protocol specification
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.LightState = exports.TurnoutState = exports.PowerState = void 0;
|
|
8
|
-
exports.powerStateToString = powerStateToString;
|
|
9
|
-
exports.turnoutStateToString = turnoutStateToString;
|
|
10
|
-
exports.lightStateToString = lightStateToString;
|
|
11
|
-
/**
|
|
12
|
-
* Power state values (from JMRI JSON protocol constants)
|
|
13
|
-
* UNKNOWN = 0 (state cannot be determined)
|
|
14
|
-
* ON = 2 (power is on)
|
|
15
|
-
* OFF = 4 (power is off)
|
|
16
|
-
*/
|
|
17
|
-
var PowerState;
|
|
18
|
-
(function (PowerState) {
|
|
19
|
-
PowerState[PowerState["UNKNOWN"] = 0] = "UNKNOWN";
|
|
20
|
-
PowerState[PowerState["ON"] = 2] = "ON";
|
|
21
|
-
PowerState[PowerState["OFF"] = 4] = "OFF";
|
|
22
|
-
})(PowerState || (exports.PowerState = PowerState = {}));
|
|
23
|
-
/**
|
|
24
|
-
* Convert PowerState enum to human-readable string
|
|
25
|
-
* @param state - The power state
|
|
26
|
-
* @returns 'ON', 'OFF', or 'UNKNOWN'
|
|
27
|
-
*/
|
|
28
|
-
function powerStateToString(state) {
|
|
29
|
-
switch (state) {
|
|
30
|
-
case PowerState.ON:
|
|
31
|
-
return 'ON';
|
|
32
|
-
case PowerState.OFF:
|
|
33
|
-
return 'OFF';
|
|
34
|
-
case PowerState.UNKNOWN:
|
|
35
|
-
return 'UNKNOWN';
|
|
36
|
-
default:
|
|
37
|
-
return 'UNKNOWN';
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Turnout state values (from JMRI JSON protocol constants)
|
|
42
|
-
* UNKNOWN = 0 (state cannot be determined)
|
|
43
|
-
* CLOSED = 2 (straight through / normal position)
|
|
44
|
-
* THROWN = 4 (diverging route position)
|
|
45
|
-
* INCONSISTENT = 8 (contradictory feedback state)
|
|
46
|
-
*/
|
|
47
|
-
var TurnoutState;
|
|
48
|
-
(function (TurnoutState) {
|
|
49
|
-
TurnoutState[TurnoutState["UNKNOWN"] = 0] = "UNKNOWN";
|
|
50
|
-
TurnoutState[TurnoutState["CLOSED"] = 2] = "CLOSED";
|
|
51
|
-
TurnoutState[TurnoutState["THROWN"] = 4] = "THROWN";
|
|
52
|
-
TurnoutState[TurnoutState["INCONSISTENT"] = 8] = "INCONSISTENT";
|
|
53
|
-
})(TurnoutState || (exports.TurnoutState = TurnoutState = {}));
|
|
54
|
-
/**
|
|
55
|
-
* Convert TurnoutState enum to human-readable string
|
|
56
|
-
*/
|
|
57
|
-
function turnoutStateToString(state) {
|
|
58
|
-
switch (state) {
|
|
59
|
-
case TurnoutState.CLOSED:
|
|
60
|
-
return 'CLOSED';
|
|
61
|
-
case TurnoutState.THROWN:
|
|
62
|
-
return 'THROWN';
|
|
63
|
-
case TurnoutState.INCONSISTENT:
|
|
64
|
-
return 'INCONSISTENT';
|
|
65
|
-
case TurnoutState.UNKNOWN:
|
|
66
|
-
default:
|
|
67
|
-
return 'UNKNOWN';
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Light state values (from JMRI JSON protocol constants)
|
|
72
|
-
* UNKNOWN = 0 (state cannot be determined)
|
|
73
|
-
* ON = 2 (light is on)
|
|
74
|
-
* OFF = 4 (light is off)
|
|
75
|
-
*/
|
|
76
|
-
var LightState;
|
|
77
|
-
(function (LightState) {
|
|
78
|
-
LightState[LightState["UNKNOWN"] = 0] = "UNKNOWN";
|
|
79
|
-
LightState[LightState["ON"] = 2] = "ON";
|
|
80
|
-
LightState[LightState["OFF"] = 4] = "OFF";
|
|
81
|
-
})(LightState || (exports.LightState = LightState = {}));
|
|
82
|
-
/**
|
|
83
|
-
* Convert LightState enum to human-readable string
|
|
84
|
-
*/
|
|
85
|
-
function lightStateToString(state) {
|
|
86
|
-
switch (state) {
|
|
87
|
-
case LightState.ON:
|
|
88
|
-
return 'ON';
|
|
89
|
-
case LightState.OFF:
|
|
90
|
-
return 'OFF';
|
|
91
|
-
case LightState.UNKNOWN:
|
|
92
|
-
default:
|
|
93
|
-
return 'UNKNOWN';
|
|
94
|
-
}
|
|
95
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Throttle-specific types
|
|
4
|
-
*/
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.isThrottleFunctionKey = isThrottleFunctionKey;
|
|
7
|
-
exports.isValidSpeed = isValidSpeed;
|
|
8
|
-
/**
|
|
9
|
-
* Validates that a value is a valid throttle function key
|
|
10
|
-
*/
|
|
11
|
-
function isThrottleFunctionKey(key) {
|
|
12
|
-
return /^F([0-9]|1[0-9]|2[0-8])$/.test(key);
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Validates that speed is in valid range (0.0 to 1.0)
|
|
16
|
-
*/
|
|
17
|
-
function isValidSpeed(speed) {
|
|
18
|
-
return typeof speed === 'number' && speed >= 0 && speed <= 1;
|
|
19
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Exponential backoff calculator with jitter
|
|
4
|
-
*/
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.calculateBackoffDelay = calculateBackoffDelay;
|
|
7
|
-
exports.shouldReconnect = shouldReconnect;
|
|
8
|
-
/**
|
|
9
|
-
* Calculate next reconnection delay using exponential backoff
|
|
10
|
-
*
|
|
11
|
-
* @param attempt - Current attempt number (1-indexed)
|
|
12
|
-
* @param options - Reconnection options
|
|
13
|
-
* @returns Delay in milliseconds
|
|
14
|
-
*/
|
|
15
|
-
function calculateBackoffDelay(attempt, options) {
|
|
16
|
-
// Base delay calculation: initialDelay * (multiplier ^ (attempt - 1))
|
|
17
|
-
const exponentialDelay = options.initialDelay * Math.pow(options.multiplier, attempt - 1);
|
|
18
|
-
// Cap at maxDelay
|
|
19
|
-
const cappedDelay = Math.min(exponentialDelay, options.maxDelay);
|
|
20
|
-
// Add jitter if enabled (±25%)
|
|
21
|
-
if (options.jitter) {
|
|
22
|
-
const jitterAmount = cappedDelay * 0.25;
|
|
23
|
-
const jitter = (Math.random() * 2 - 1) * jitterAmount; // Random between -25% and +25%
|
|
24
|
-
return Math.max(0, Math.round(cappedDelay + jitter));
|
|
25
|
-
}
|
|
26
|
-
return Math.round(cappedDelay);
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Check if should attempt reconnection
|
|
30
|
-
*
|
|
31
|
-
* @param attempt - Current attempt number (1-indexed)
|
|
32
|
-
* @param maxAttempts - Maximum attempts (0 = infinite)
|
|
33
|
-
* @returns True if should attempt reconnection
|
|
34
|
-
*/
|
|
35
|
-
function shouldReconnect(attempt, maxAttempts) {
|
|
36
|
-
if (maxAttempts === 0) {
|
|
37
|
-
return true; // Infinite attempts
|
|
38
|
-
}
|
|
39
|
-
return attempt <= maxAttempts;
|
|
40
|
-
}
|
package/dist/cjs/utils/index.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Utility functions
|
|
4
|
-
*/
|
|
5
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
-
if (k2 === undefined) k2 = k;
|
|
7
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
-
}
|
|
11
|
-
Object.defineProperty(o, k2, desc);
|
|
12
|
-
}) : (function(o, m, k, k2) {
|
|
13
|
-
if (k2 === undefined) k2 = k;
|
|
14
|
-
o[k2] = m[k];
|
|
15
|
-
}));
|
|
16
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
17
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
18
|
-
};
|
|
19
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
-
__exportStar(require("./message-id.js"), exports);
|
|
21
|
-
__exportStar(require("./exponential-backoff.js"), exports);
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Message ID generator for request/response correlation
|
|
4
|
-
*/
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.MessageIdGenerator = void 0;
|
|
7
|
-
/**
|
|
8
|
-
* Sequential message ID generator
|
|
9
|
-
* Provides unique IDs for correlating requests and responses
|
|
10
|
-
*/
|
|
11
|
-
class MessageIdGenerator {
|
|
12
|
-
constructor() {
|
|
13
|
-
this.currentId = 0;
|
|
14
|
-
this.maxId = Number.MAX_SAFE_INTEGER;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Generate next sequential ID
|
|
18
|
-
* Wraps around at MAX_SAFE_INTEGER
|
|
19
|
-
*/
|
|
20
|
-
next() {
|
|
21
|
-
this.currentId++;
|
|
22
|
-
if (this.currentId >= this.maxId) {
|
|
23
|
-
this.currentId = 1;
|
|
24
|
-
}
|
|
25
|
-
return this.currentId;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Reset ID counter to 0
|
|
29
|
-
*/
|
|
30
|
-
reset() {
|
|
31
|
-
this.currentId = 0;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Get current ID without incrementing
|
|
35
|
-
*/
|
|
36
|
-
current() {
|
|
37
|
-
return this.currentId;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
exports.MessageIdGenerator = MessageIdGenerator;
|
package/dist/esm/client.js
DELETED
|
@@ -1,362 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Main JMRI client class
|
|
3
|
-
*/
|
|
4
|
-
import { EventEmitter } from 'eventemitter3';
|
|
5
|
-
import { WebSocketClient } from './core/websocket-client.js';
|
|
6
|
-
import { PowerManager } from './managers/power-manager.js';
|
|
7
|
-
import { RosterManager } from './managers/roster-manager.js';
|
|
8
|
-
import { ThrottleManager } from './managers/throttle-manager.js';
|
|
9
|
-
import { TurnoutManager } from './managers/turnout-manager.js';
|
|
10
|
-
import { LightManager } from './managers/light-manager.js';
|
|
11
|
-
import { SystemConnectionsManager } from './managers/system-connections-manager.js';
|
|
12
|
-
import { mergeOptions } from './types/client-options.js';
|
|
13
|
-
/**
|
|
14
|
-
* JMRI WebSocket Client
|
|
15
|
-
* Provides event-driven interface to JMRI with throttle control
|
|
16
|
-
*/
|
|
17
|
-
export class JmriClient extends EventEmitter {
|
|
18
|
-
/**
|
|
19
|
-
* Create a new JMRI client
|
|
20
|
-
*
|
|
21
|
-
* @param options - Client configuration options
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* ```typescript
|
|
25
|
-
* const client = new JmriClient({
|
|
26
|
-
* host: 'jmri.local',
|
|
27
|
-
* port: 12080
|
|
28
|
-
* });
|
|
29
|
-
*
|
|
30
|
-
* client.on('connected', () => console.log('Connected!'));
|
|
31
|
-
* client.on('power:changed', (state) => console.log('Power:', state));
|
|
32
|
-
* ```
|
|
33
|
-
*/
|
|
34
|
-
constructor(options) {
|
|
35
|
-
super();
|
|
36
|
-
// Merge options with defaults
|
|
37
|
-
this.options = mergeOptions(options);
|
|
38
|
-
// Create WebSocket client
|
|
39
|
-
this.wsClient = new WebSocketClient(this.options);
|
|
40
|
-
// Create managers
|
|
41
|
-
this.powerManager = new PowerManager(this.wsClient);
|
|
42
|
-
this.rosterManager = new RosterManager(this.wsClient);
|
|
43
|
-
this.throttleManager = new ThrottleManager(this.wsClient);
|
|
44
|
-
this.turnoutManager = new TurnoutManager(this.wsClient);
|
|
45
|
-
this.lightManager = new LightManager(this.wsClient);
|
|
46
|
-
this.systemConnectionsManager = new SystemConnectionsManager(this.wsClient);
|
|
47
|
-
// Forward events from WebSocket client
|
|
48
|
-
this.wsClient.on('connected', () => this.emit('connected'));
|
|
49
|
-
this.wsClient.on('disconnected', (reason) => this.emit('disconnected', reason));
|
|
50
|
-
this.wsClient.on('reconnecting', (attempt, delay) => this.emit('reconnecting', attempt, delay));
|
|
51
|
-
this.wsClient.on('reconnected', () => this.emit('reconnected'));
|
|
52
|
-
this.wsClient.on('reconnectionFailed', (attempts) => this.emit('reconnectionFailed', attempts));
|
|
53
|
-
this.wsClient.on('connectionStateChanged', (state) => this.emit('connectionStateChanged', state));
|
|
54
|
-
this.wsClient.on('error', (error) => this.emit('error', error));
|
|
55
|
-
this.wsClient.on('heartbeat:sent', () => this.emit('heartbeat:sent'));
|
|
56
|
-
this.wsClient.on('heartbeat:timeout', () => this.emit('heartbeat:timeout'));
|
|
57
|
-
this.wsClient.on('hello', (data) => this.emit('hello', data));
|
|
58
|
-
// Forward events from managers
|
|
59
|
-
this.powerManager.on('power:changed', (state) => this.emit('power:changed', state));
|
|
60
|
-
this.turnoutManager.on('turnout:changed', (name, state) => this.emit('turnout:changed', name, state));
|
|
61
|
-
this.lightManager.on('light:changed', (name, state) => this.emit('light:changed', name, state));
|
|
62
|
-
this.throttleManager.on('throttle:acquired', (id) => this.emit('throttle:acquired', id));
|
|
63
|
-
this.throttleManager.on('throttle:updated', (id, data) => this.emit('throttle:updated', id, data));
|
|
64
|
-
this.throttleManager.on('throttle:released', (id) => this.emit('throttle:released', id));
|
|
65
|
-
this.throttleManager.on('throttle:lost', (id) => this.emit('throttle:lost', id));
|
|
66
|
-
// Auto-connect if enabled
|
|
67
|
-
if (this.options.autoConnect) {
|
|
68
|
-
this.connect().catch((error) => {
|
|
69
|
-
this.emit('error', error);
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Connect to JMRI server
|
|
75
|
-
*/
|
|
76
|
-
async connect() {
|
|
77
|
-
return this.wsClient.connect();
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Disconnect from JMRI server
|
|
81
|
-
* Releases all throttles and closes connection
|
|
82
|
-
*/
|
|
83
|
-
async disconnect() {
|
|
84
|
-
// Release all throttles first
|
|
85
|
-
await this.throttleManager.releaseAllThrottles();
|
|
86
|
-
// Disconnect WebSocket
|
|
87
|
-
return this.wsClient.disconnect();
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Get current connection state
|
|
91
|
-
*/
|
|
92
|
-
getConnectionState() {
|
|
93
|
-
return this.wsClient.getState();
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Check if connected to JMRI
|
|
97
|
-
*/
|
|
98
|
-
isConnected() {
|
|
99
|
-
return this.wsClient.isConnected();
|
|
100
|
-
}
|
|
101
|
-
// ============================================================================
|
|
102
|
-
// Power Control
|
|
103
|
-
// ============================================================================
|
|
104
|
-
/**
|
|
105
|
-
* Get current track power state
|
|
106
|
-
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
107
|
-
*/
|
|
108
|
-
async getPower(prefix) {
|
|
109
|
-
return this.powerManager.getPower(prefix);
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
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
|
|
115
|
-
*/
|
|
116
|
-
async setPower(state, prefix) {
|
|
117
|
-
return this.powerManager.setPower(state, prefix);
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Turn track power on
|
|
121
|
-
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
122
|
-
*/
|
|
123
|
-
async powerOn(prefix) {
|
|
124
|
-
return this.powerManager.powerOn(prefix);
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Turn track power off
|
|
128
|
-
* @param prefix - Optional JMRI connection prefix to target a specific hardware connection
|
|
129
|
-
*/
|
|
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();
|
|
150
|
-
}
|
|
151
|
-
// ============================================================================
|
|
152
|
-
// Roster Management
|
|
153
|
-
// ============================================================================
|
|
154
|
-
/**
|
|
155
|
-
* Get all roster entries
|
|
156
|
-
*/
|
|
157
|
-
async getRoster() {
|
|
158
|
-
return this.rosterManager.getRoster();
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Get roster entry by name
|
|
162
|
-
*/
|
|
163
|
-
async getRosterEntryByName(name) {
|
|
164
|
-
return this.rosterManager.getRosterEntryByName(name);
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Get roster entry by address
|
|
168
|
-
*/
|
|
169
|
-
async getRosterEntryByAddress(address) {
|
|
170
|
-
return this.rosterManager.getRosterEntryByAddress(address);
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Search roster by partial name match
|
|
174
|
-
*/
|
|
175
|
-
async searchRoster(query) {
|
|
176
|
-
return this.rosterManager.searchRoster(query);
|
|
177
|
-
}
|
|
178
|
-
// ============================================================================
|
|
179
|
-
// Turnout Control
|
|
180
|
-
// ============================================================================
|
|
181
|
-
/**
|
|
182
|
-
* Get the current state of a turnout
|
|
183
|
-
*/
|
|
184
|
-
async getTurnout(name) {
|
|
185
|
-
return this.turnoutManager.getTurnout(name);
|
|
186
|
-
}
|
|
187
|
-
/**
|
|
188
|
-
* Set a turnout to the given state
|
|
189
|
-
*/
|
|
190
|
-
async setTurnout(name, state) {
|
|
191
|
-
return this.turnoutManager.setTurnout(name, state);
|
|
192
|
-
}
|
|
193
|
-
/**
|
|
194
|
-
* Throw a turnout (diverging route)
|
|
195
|
-
*/
|
|
196
|
-
async throwTurnout(name) {
|
|
197
|
-
return this.turnoutManager.throwTurnout(name);
|
|
198
|
-
}
|
|
199
|
-
/**
|
|
200
|
-
* Close a turnout (straight through / normal)
|
|
201
|
-
*/
|
|
202
|
-
async closeTurnout(name) {
|
|
203
|
-
return this.turnoutManager.closeTurnout(name);
|
|
204
|
-
}
|
|
205
|
-
/**
|
|
206
|
-
* List all turnouts known to JMRI
|
|
207
|
-
*/
|
|
208
|
-
async listTurnouts() {
|
|
209
|
-
return this.turnoutManager.listTurnouts();
|
|
210
|
-
}
|
|
211
|
-
/**
|
|
212
|
-
* Get cached turnout state without a network request
|
|
213
|
-
*/
|
|
214
|
-
getTurnoutState(name) {
|
|
215
|
-
return this.turnoutManager.getTurnoutState(name);
|
|
216
|
-
}
|
|
217
|
-
/**
|
|
218
|
-
* Get all cached turnout states
|
|
219
|
-
*/
|
|
220
|
-
getCachedTurnouts() {
|
|
221
|
-
return this.turnoutManager.getCachedTurnouts();
|
|
222
|
-
}
|
|
223
|
-
// ============================================================================
|
|
224
|
-
// Light Control
|
|
225
|
-
// ============================================================================
|
|
226
|
-
/**
|
|
227
|
-
* Get the current state of a light
|
|
228
|
-
*/
|
|
229
|
-
async getLight(name) {
|
|
230
|
-
return this.lightManager.getLight(name);
|
|
231
|
-
}
|
|
232
|
-
/**
|
|
233
|
-
* Set a light to the given state
|
|
234
|
-
*/
|
|
235
|
-
async setLight(name, state) {
|
|
236
|
-
return this.lightManager.setLight(name, state);
|
|
237
|
-
}
|
|
238
|
-
/**
|
|
239
|
-
* Turn a light on
|
|
240
|
-
*/
|
|
241
|
-
async turnOnLight(name) {
|
|
242
|
-
return this.lightManager.turnOnLight(name);
|
|
243
|
-
}
|
|
244
|
-
/**
|
|
245
|
-
* Turn a light off
|
|
246
|
-
*/
|
|
247
|
-
async turnOffLight(name) {
|
|
248
|
-
return this.lightManager.turnOffLight(name);
|
|
249
|
-
}
|
|
250
|
-
/**
|
|
251
|
-
* List all lights known to JMRI
|
|
252
|
-
*/
|
|
253
|
-
async listLights() {
|
|
254
|
-
return this.lightManager.listLights();
|
|
255
|
-
}
|
|
256
|
-
/**
|
|
257
|
-
* Get cached light state without a network request
|
|
258
|
-
*/
|
|
259
|
-
getLightState(name) {
|
|
260
|
-
return this.lightManager.getLightState(name);
|
|
261
|
-
}
|
|
262
|
-
/**
|
|
263
|
-
* Get all cached light states
|
|
264
|
-
*/
|
|
265
|
-
getCachedLights() {
|
|
266
|
-
return this.lightManager.getCachedLights();
|
|
267
|
-
}
|
|
268
|
-
// ============================================================================
|
|
269
|
-
// Throttle Control
|
|
270
|
-
// ============================================================================
|
|
271
|
-
/**
|
|
272
|
-
* Acquire a throttle for a locomotive
|
|
273
|
-
*
|
|
274
|
-
* @param options - Throttle acquisition options
|
|
275
|
-
* @returns Throttle ID for use in other throttle methods
|
|
276
|
-
*
|
|
277
|
-
* @example
|
|
278
|
-
* ```typescript
|
|
279
|
-
* const throttleId = await client.acquireThrottle({ address: 3 });
|
|
280
|
-
* await client.setThrottleSpeed(throttleId, 0.5); // Half speed
|
|
281
|
-
* ```
|
|
282
|
-
*/
|
|
283
|
-
async acquireThrottle(options) {
|
|
284
|
-
return this.throttleManager.acquireThrottle(options);
|
|
285
|
-
}
|
|
286
|
-
/**
|
|
287
|
-
* Release a throttle
|
|
288
|
-
*/
|
|
289
|
-
async releaseThrottle(throttleId) {
|
|
290
|
-
return this.throttleManager.releaseThrottle(throttleId);
|
|
291
|
-
}
|
|
292
|
-
/**
|
|
293
|
-
* Set throttle speed (0.0 to 1.0)
|
|
294
|
-
*
|
|
295
|
-
* @param throttleId - Throttle ID from acquireThrottle
|
|
296
|
-
* @param speed - Speed value between 0.0 (stopped) and 1.0 (full speed)
|
|
297
|
-
*/
|
|
298
|
-
async setThrottleSpeed(throttleId, speed) {
|
|
299
|
-
return this.throttleManager.setSpeed(throttleId, speed);
|
|
300
|
-
}
|
|
301
|
-
/**
|
|
302
|
-
* Set throttle direction
|
|
303
|
-
*
|
|
304
|
-
* @param throttleId - Throttle ID from acquireThrottle
|
|
305
|
-
* @param forward - True for forward, false for reverse
|
|
306
|
-
*/
|
|
307
|
-
async setThrottleDirection(throttleId, forward) {
|
|
308
|
-
return this.throttleManager.setDirection(throttleId, forward);
|
|
309
|
-
}
|
|
310
|
-
/**
|
|
311
|
-
* Set throttle function (F0-F28)
|
|
312
|
-
*
|
|
313
|
-
* @param throttleId - Throttle ID from acquireThrottle
|
|
314
|
-
* @param functionKey - Function key (F0-F28)
|
|
315
|
-
* @param value - True to activate, false to deactivate
|
|
316
|
-
*
|
|
317
|
-
* @example
|
|
318
|
-
* ```typescript
|
|
319
|
-
* await client.setThrottleFunction(throttleId, 'F0', true); // Headlight on
|
|
320
|
-
* await client.setThrottleFunction(throttleId, 'F2', true); // Horn
|
|
321
|
-
* ```
|
|
322
|
-
*/
|
|
323
|
-
async setThrottleFunction(throttleId, functionKey, value) {
|
|
324
|
-
return this.throttleManager.setFunction(throttleId, functionKey, value);
|
|
325
|
-
}
|
|
326
|
-
/**
|
|
327
|
-
* Emergency stop for a throttle (speed to 0)
|
|
328
|
-
*/
|
|
329
|
-
async emergencyStop(throttleId) {
|
|
330
|
-
return this.throttleManager.emergencyStop(throttleId);
|
|
331
|
-
}
|
|
332
|
-
/**
|
|
333
|
-
* Set throttle to idle (speed to 0, maintain direction)
|
|
334
|
-
*/
|
|
335
|
-
async idleThrottle(throttleId) {
|
|
336
|
-
return this.throttleManager.idle(throttleId);
|
|
337
|
-
}
|
|
338
|
-
/**
|
|
339
|
-
* Get throttle state
|
|
340
|
-
*/
|
|
341
|
-
getThrottleState(throttleId) {
|
|
342
|
-
return this.throttleManager.getThrottleState(throttleId);
|
|
343
|
-
}
|
|
344
|
-
/**
|
|
345
|
-
* Get all throttle IDs
|
|
346
|
-
*/
|
|
347
|
-
getThrottleIds() {
|
|
348
|
-
return this.throttleManager.getThrottleIds();
|
|
349
|
-
}
|
|
350
|
-
/**
|
|
351
|
-
* Get all throttle states
|
|
352
|
-
*/
|
|
353
|
-
getAllThrottles() {
|
|
354
|
-
return this.throttleManager.getAllThrottles();
|
|
355
|
-
}
|
|
356
|
-
/**
|
|
357
|
-
* Release all throttles
|
|
358
|
-
*/
|
|
359
|
-
async releaseAllThrottles() {
|
|
360
|
-
return this.throttleManager.releaseAllThrottles();
|
|
361
|
-
}
|
|
362
|
-
}
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Connection state management with state machine
|
|
3
|
-
*/
|
|
4
|
-
import { EventEmitter } from 'eventemitter3';
|
|
5
|
-
import { ConnectionState } from '../types/events.js';
|
|
6
|
-
/**
|
|
7
|
-
* Valid state transitions
|
|
8
|
-
*/
|
|
9
|
-
const VALID_TRANSITIONS = {
|
|
10
|
-
[ConnectionState.DISCONNECTED]: [ConnectionState.CONNECTING],
|
|
11
|
-
[ConnectionState.CONNECTING]: [ConnectionState.CONNECTED, ConnectionState.DISCONNECTED],
|
|
12
|
-
[ConnectionState.CONNECTED]: [ConnectionState.DISCONNECTED, ConnectionState.RECONNECTING],
|
|
13
|
-
[ConnectionState.RECONNECTING]: [ConnectionState.CONNECTING, ConnectionState.CONNECTED, ConnectionState.DISCONNECTED]
|
|
14
|
-
};
|
|
15
|
-
/**
|
|
16
|
-
* Manages connection state with validation
|
|
17
|
-
*/
|
|
18
|
-
export class ConnectionStateManager extends EventEmitter {
|
|
19
|
-
constructor() {
|
|
20
|
-
super(...arguments);
|
|
21
|
-
this.currentState = ConnectionState.DISCONNECTED;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Get current connection state
|
|
25
|
-
*/
|
|
26
|
-
getState() {
|
|
27
|
-
return this.currentState;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Check if currently connected
|
|
31
|
-
*/
|
|
32
|
-
isConnected() {
|
|
33
|
-
return this.currentState === ConnectionState.CONNECTED;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Check if currently connecting
|
|
37
|
-
*/
|
|
38
|
-
isConnecting() {
|
|
39
|
-
return this.currentState === ConnectionState.CONNECTING;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Check if currently disconnected
|
|
43
|
-
*/
|
|
44
|
-
isDisconnected() {
|
|
45
|
-
return this.currentState === ConnectionState.DISCONNECTED;
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Check if currently reconnecting
|
|
49
|
-
*/
|
|
50
|
-
isReconnecting() {
|
|
51
|
-
return this.currentState === ConnectionState.RECONNECTING;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Transition to new state
|
|
55
|
-
* Validates transition and emits event
|
|
56
|
-
*/
|
|
57
|
-
transition(newState) {
|
|
58
|
-
const validTransitions = VALID_TRANSITIONS[this.currentState];
|
|
59
|
-
if (!validTransitions.includes(newState)) {
|
|
60
|
-
throw new Error(`Invalid state transition: ${this.currentState} -> ${newState}`);
|
|
61
|
-
}
|
|
62
|
-
const previousState = this.currentState;
|
|
63
|
-
this.currentState = newState;
|
|
64
|
-
this.emit('stateChanged', newState, previousState);
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Force state without validation (use with caution)
|
|
68
|
-
*/
|
|
69
|
-
forceState(newState) {
|
|
70
|
-
const previousState = this.currentState;
|
|
71
|
-
this.currentState = newState;
|
|
72
|
-
this.emit('stateChanged', newState, previousState);
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Reset to disconnected state
|
|
76
|
-
*/
|
|
77
|
-
reset() {
|
|
78
|
-
this.forceState(ConnectionState.DISCONNECTED);
|
|
79
|
-
}
|
|
80
|
-
}
|