jmri-client 3.5.1 → 3.6.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/dist/browser/jmri-client.js +213 -2
- package/dist/cjs/client.js +48 -1
- package/dist/cjs/core/connection-state-manager.js +0 -1
- package/dist/cjs/core/heartbeat-manager.js +0 -1
- package/dist/cjs/core/index.js +0 -1
- package/dist/cjs/core/message-queue.js +0 -1
- package/dist/cjs/core/reconnection-manager.js +0 -1
- package/dist/cjs/core/websocket-adapter.js +0 -1
- package/dist/cjs/core/websocket-client.js +0 -1
- package/dist/cjs/index.js +3 -2
- package/dist/cjs/managers/index.js +1 -1
- package/dist/cjs/managers/power-manager.js +0 -1
- package/dist/cjs/managers/roster-manager.js +0 -1
- package/dist/cjs/managers/throttle-manager.js +0 -1
- package/dist/cjs/managers/turnout-manager.js +109 -0
- package/dist/cjs/mocks/index.js +0 -1
- package/dist/cjs/mocks/mock-data.js +7 -1
- package/dist/cjs/mocks/mock-response-manager.js +38 -1
- package/dist/cjs/types/client-options.js +0 -1
- package/dist/cjs/types/events.js +0 -1
- package/dist/cjs/types/index.js +0 -1
- package/dist/cjs/types/jmri-messages.js +32 -2
- package/dist/cjs/types/throttle.js +0 -1
- package/dist/cjs/utils/exponential-backoff.js +0 -1
- package/dist/cjs/utils/index.js +0 -1
- package/dist/cjs/utils/message-id.js +0 -1
- package/dist/esm/client.js +48 -1
- package/dist/esm/core/connection-state-manager.js +0 -1
- package/dist/esm/core/heartbeat-manager.js +0 -1
- package/dist/esm/core/index.js +0 -1
- package/dist/esm/core/message-queue.js +0 -1
- package/dist/esm/core/reconnection-manager.js +0 -1
- package/dist/esm/core/websocket-adapter.js +0 -1
- package/dist/esm/core/websocket-client.js +0 -1
- package/dist/esm/index.js +2 -3
- package/dist/esm/managers/index.js +1 -1
- package/dist/esm/managers/power-manager.js +0 -1
- package/dist/esm/managers/roster-manager.js +0 -1
- package/dist/esm/managers/throttle-manager.js +0 -1
- package/dist/esm/managers/turnout-manager.js +105 -0
- package/dist/esm/mocks/index.js +0 -1
- package/dist/esm/mocks/mock-data.js +7 -1
- package/dist/esm/mocks/mock-response-manager.js +39 -2
- package/dist/esm/types/client-options.js +0 -1
- package/dist/esm/types/events.js +0 -1
- package/dist/esm/types/index.js +0 -1
- package/dist/esm/types/jmri-messages.js +30 -1
- package/dist/esm/types/throttle.js +0 -1
- package/dist/esm/utils/exponential-backoff.js +0 -1
- package/dist/esm/utils/index.js +0 -1
- package/dist/esm/utils/message-id.js +0 -1
- package/dist/types/client.d.ts +30 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/managers/index.d.ts +1 -0
- package/dist/types/managers/turnout-manager.d.ts +47 -0
- package/dist/types/mocks/mock-data.d.ts +24 -0
- package/dist/types/mocks/mock-response-manager.d.ts +10 -1
- package/dist/types/types/events.d.ts +2 -1
- package/dist/types/types/jmri-messages.d.ts +35 -1
- package/package.json +5 -1
- package/dist/browser/jmri-client.js.map +0 -7
- package/dist/cjs/client.js.map +0 -1
- package/dist/cjs/core/connection-state-manager.js.map +0 -1
- package/dist/cjs/core/heartbeat-manager.js.map +0 -1
- package/dist/cjs/core/index.js.map +0 -1
- package/dist/cjs/core/message-queue.js.map +0 -1
- package/dist/cjs/core/reconnection-manager.js.map +0 -1
- package/dist/cjs/core/websocket-adapter.js.map +0 -1
- package/dist/cjs/core/websocket-client.js.map +0 -1
- package/dist/cjs/index.js.map +0 -1
- package/dist/cjs/managers/index.js.map +0 -1
- package/dist/cjs/managers/power-manager.js.map +0 -1
- package/dist/cjs/managers/roster-manager.js.map +0 -1
- package/dist/cjs/managers/throttle-manager.js.map +0 -1
- package/dist/cjs/mocks/index.js.map +0 -1
- package/dist/cjs/mocks/mock-data.js.map +0 -1
- package/dist/cjs/mocks/mock-response-manager.js.map +0 -1
- package/dist/cjs/types/client-options.js.map +0 -1
- package/dist/cjs/types/events.js.map +0 -1
- package/dist/cjs/types/index.js.map +0 -1
- package/dist/cjs/types/jmri-messages.js.map +0 -1
- package/dist/cjs/types/throttle.js.map +0 -1
- package/dist/cjs/utils/exponential-backoff.js.map +0 -1
- package/dist/cjs/utils/index.js.map +0 -1
- package/dist/cjs/utils/message-id.js.map +0 -1
- package/dist/esm/client.js.map +0 -1
- package/dist/esm/core/connection-state-manager.js.map +0 -1
- package/dist/esm/core/heartbeat-manager.js.map +0 -1
- package/dist/esm/core/index.js.map +0 -1
- package/dist/esm/core/message-queue.js.map +0 -1
- package/dist/esm/core/reconnection-manager.js.map +0 -1
- package/dist/esm/core/websocket-adapter.js.map +0 -1
- package/dist/esm/core/websocket-client.js.map +0 -1
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/managers/index.js.map +0 -1
- package/dist/esm/managers/power-manager.js.map +0 -1
- package/dist/esm/managers/roster-manager.js.map +0 -1
- package/dist/esm/managers/throttle-manager.js.map +0 -1
- package/dist/esm/mocks/index.js.map +0 -1
- package/dist/esm/mocks/mock-data.js.map +0 -1
- package/dist/esm/mocks/mock-response-manager.js.map +0 -1
- package/dist/esm/types/client-options.js.map +0 -1
- package/dist/esm/types/events.js.map +0 -1
- package/dist/esm/types/index.js.map +0 -1
- package/dist/esm/types/jmri-messages.js.map +0 -1
- package/dist/esm/types/throttle.js.map +0 -1
- package/dist/esm/utils/exponential-backoff.js.map +0 -1
- package/dist/esm/utils/index.js.map +0 -1
- package/dist/esm/utils/message-id.js.map +0 -1
|
@@ -618,6 +618,26 @@ function powerStateToString(state) {
|
|
|
618
618
|
return "UNKNOWN";
|
|
619
619
|
}
|
|
620
620
|
}
|
|
621
|
+
var TurnoutState = /* @__PURE__ */ ((TurnoutState2) => {
|
|
622
|
+
TurnoutState2[TurnoutState2["UNKNOWN"] = 0] = "UNKNOWN";
|
|
623
|
+
TurnoutState2[TurnoutState2["CLOSED"] = 2] = "CLOSED";
|
|
624
|
+
TurnoutState2[TurnoutState2["THROWN"] = 4] = "THROWN";
|
|
625
|
+
TurnoutState2[TurnoutState2["INCONSISTENT"] = 8] = "INCONSISTENT";
|
|
626
|
+
return TurnoutState2;
|
|
627
|
+
})(TurnoutState || {});
|
|
628
|
+
function turnoutStateToString(state) {
|
|
629
|
+
switch (state) {
|
|
630
|
+
case 2 /* CLOSED */:
|
|
631
|
+
return "CLOSED";
|
|
632
|
+
case 4 /* THROWN */:
|
|
633
|
+
return "THROWN";
|
|
634
|
+
case 8 /* INCONSISTENT */:
|
|
635
|
+
return "INCONSISTENT";
|
|
636
|
+
case 0 /* UNKNOWN */:
|
|
637
|
+
default:
|
|
638
|
+
return "UNKNOWN";
|
|
639
|
+
}
|
|
640
|
+
}
|
|
621
641
|
|
|
622
642
|
// src/mocks/mock-data.ts
|
|
623
643
|
var mockData = {
|
|
@@ -803,6 +823,13 @@ var mockData = {
|
|
|
803
823
|
}
|
|
804
824
|
}
|
|
805
825
|
},
|
|
826
|
+
"turnout": {
|
|
827
|
+
"list": [
|
|
828
|
+
{ "type": "turnout", "data": { "name": "LT1", "userName": "Main Diverge", "state": 2 } },
|
|
829
|
+
{ "type": "turnout", "data": { "name": "LT2", "userName": "Yard Lead", "state": 2 } },
|
|
830
|
+
{ "type": "turnout", "data": { "name": "LT3", "userName": "Siding Entry", "state": 4 } }
|
|
831
|
+
]
|
|
832
|
+
},
|
|
806
833
|
"ping": {
|
|
807
834
|
"type": "ping"
|
|
808
835
|
},
|
|
@@ -841,6 +868,11 @@ var mockData = {
|
|
|
841
868
|
var MockResponseManager = class {
|
|
842
869
|
constructor(options = {}) {
|
|
843
870
|
this.throttles = /* @__PURE__ */ new Map();
|
|
871
|
+
this.turnouts = /* @__PURE__ */ new Map([
|
|
872
|
+
["LT1", 2 /* CLOSED */],
|
|
873
|
+
["LT2", 2 /* CLOSED */],
|
|
874
|
+
["LT3", 4 /* THROWN */]
|
|
875
|
+
]);
|
|
844
876
|
this.responseDelay = options.responseDelay ?? 50;
|
|
845
877
|
this.powerState = options.initialPowerState ?? 4 /* OFF */;
|
|
846
878
|
}
|
|
@@ -860,6 +892,8 @@ var MockResponseManager = class {
|
|
|
860
892
|
return this.getRosterResponse(message);
|
|
861
893
|
case "throttle":
|
|
862
894
|
return this.getThrottleResponse(message);
|
|
895
|
+
case "turnout":
|
|
896
|
+
return this.getTurnoutResponse(message);
|
|
863
897
|
case "ping":
|
|
864
898
|
return this.getPingResponse();
|
|
865
899
|
case "goodbye":
|
|
@@ -975,6 +1009,23 @@ var MockResponseManager = class {
|
|
|
975
1009
|
data: {}
|
|
976
1010
|
};
|
|
977
1011
|
}
|
|
1012
|
+
/**
|
|
1013
|
+
* Get turnout response
|
|
1014
|
+
*/
|
|
1015
|
+
getTurnoutResponse(message) {
|
|
1016
|
+
if (message.method === "list") {
|
|
1017
|
+
return JSON.parse(JSON.stringify(mockData.turnout.list));
|
|
1018
|
+
}
|
|
1019
|
+
const name = message.data?.name;
|
|
1020
|
+
if (!name) {
|
|
1021
|
+
return { type: "turnout", data: { name: "", state: 0 /* UNKNOWN */ } };
|
|
1022
|
+
}
|
|
1023
|
+
if (message.method === "post" && message.data?.state !== void 0) {
|
|
1024
|
+
this.turnouts.set(name, message.data.state);
|
|
1025
|
+
}
|
|
1026
|
+
const state = this.turnouts.get(name) ?? 0 /* UNKNOWN */;
|
|
1027
|
+
return { type: "turnout", data: { name, state } };
|
|
1028
|
+
}
|
|
978
1029
|
/**
|
|
979
1030
|
* Get ping response (pong)
|
|
980
1031
|
*/
|
|
@@ -1005,12 +1056,23 @@ var MockResponseManager = class {
|
|
|
1005
1056
|
getThrottles() {
|
|
1006
1057
|
return this.throttles;
|
|
1007
1058
|
}
|
|
1059
|
+
/**
|
|
1060
|
+
* Get all turnout states (for testing)
|
|
1061
|
+
*/
|
|
1062
|
+
getTurnouts() {
|
|
1063
|
+
return this.turnouts;
|
|
1064
|
+
}
|
|
1008
1065
|
/**
|
|
1009
1066
|
* Reset all state (for testing)
|
|
1010
1067
|
*/
|
|
1011
1068
|
reset() {
|
|
1012
1069
|
this.powerState = 4 /* OFF */;
|
|
1013
1070
|
this.throttles.clear();
|
|
1071
|
+
this.turnouts = /* @__PURE__ */ new Map([
|
|
1072
|
+
["LT1", 2 /* CLOSED */],
|
|
1073
|
+
["LT2", 2 /* CLOSED */],
|
|
1074
|
+
["LT3", 4 /* THROWN */]
|
|
1075
|
+
]);
|
|
1014
1076
|
}
|
|
1015
1077
|
/**
|
|
1016
1078
|
* Delay helper
|
|
@@ -1730,6 +1792,104 @@ var ThrottleManager = class extends import_index.default {
|
|
|
1730
1792
|
}
|
|
1731
1793
|
};
|
|
1732
1794
|
|
|
1795
|
+
// src/managers/turnout-manager.ts
|
|
1796
|
+
var TurnoutManager = class extends import_index.default {
|
|
1797
|
+
constructor(client) {
|
|
1798
|
+
super();
|
|
1799
|
+
this.turnouts = /* @__PURE__ */ new Map();
|
|
1800
|
+
this.client = client;
|
|
1801
|
+
this.client.on("update", (message) => {
|
|
1802
|
+
if (message.type === "turnout") {
|
|
1803
|
+
this.handleTurnoutUpdate(message);
|
|
1804
|
+
}
|
|
1805
|
+
});
|
|
1806
|
+
}
|
|
1807
|
+
/**
|
|
1808
|
+
* Get the current state of a turnout.
|
|
1809
|
+
* Also registers a server-side listener so subsequent changes are pushed.
|
|
1810
|
+
*/
|
|
1811
|
+
async getTurnout(name) {
|
|
1812
|
+
const message = {
|
|
1813
|
+
type: "turnout",
|
|
1814
|
+
data: { name }
|
|
1815
|
+
};
|
|
1816
|
+
const response = await this.client.request(message);
|
|
1817
|
+
const state = response.data?.state ?? 0 /* UNKNOWN */;
|
|
1818
|
+
this.turnouts.set(name, state);
|
|
1819
|
+
return state;
|
|
1820
|
+
}
|
|
1821
|
+
/**
|
|
1822
|
+
* Set a turnout to the given state
|
|
1823
|
+
*/
|
|
1824
|
+
async setTurnout(name, state) {
|
|
1825
|
+
const message = {
|
|
1826
|
+
type: "turnout",
|
|
1827
|
+
method: "post",
|
|
1828
|
+
data: { name, state }
|
|
1829
|
+
};
|
|
1830
|
+
await this.client.request(message);
|
|
1831
|
+
const oldState = this.turnouts.get(name);
|
|
1832
|
+
this.turnouts.set(name, state);
|
|
1833
|
+
if (oldState !== state) {
|
|
1834
|
+
this.emit("turnout:changed", name, state);
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
/**
|
|
1838
|
+
* Throw a turnout (diverging route)
|
|
1839
|
+
*/
|
|
1840
|
+
async throwTurnout(name) {
|
|
1841
|
+
return this.setTurnout(name, 4 /* THROWN */);
|
|
1842
|
+
}
|
|
1843
|
+
/**
|
|
1844
|
+
* Close a turnout (straight through / normal)
|
|
1845
|
+
*/
|
|
1846
|
+
async closeTurnout(name) {
|
|
1847
|
+
return this.setTurnout(name, 2 /* CLOSED */);
|
|
1848
|
+
}
|
|
1849
|
+
/**
|
|
1850
|
+
* List all turnouts known to JMRI
|
|
1851
|
+
*/
|
|
1852
|
+
async listTurnouts() {
|
|
1853
|
+
const message = {
|
|
1854
|
+
type: "turnout",
|
|
1855
|
+
method: "list"
|
|
1856
|
+
};
|
|
1857
|
+
const response = await this.client.request(message);
|
|
1858
|
+
const entries = Array.isArray(response) ? response.map((r) => r.data ?? r) : [];
|
|
1859
|
+
for (const entry of entries) {
|
|
1860
|
+
if (entry.name && entry.state !== void 0) {
|
|
1861
|
+
this.turnouts.set(entry.name, entry.state);
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1864
|
+
return entries;
|
|
1865
|
+
}
|
|
1866
|
+
/**
|
|
1867
|
+
* Get cached turnout state without a network request
|
|
1868
|
+
*/
|
|
1869
|
+
getTurnoutState(name) {
|
|
1870
|
+
return this.turnouts.get(name);
|
|
1871
|
+
}
|
|
1872
|
+
/**
|
|
1873
|
+
* Get all cached turnout states
|
|
1874
|
+
*/
|
|
1875
|
+
getCachedTurnouts() {
|
|
1876
|
+
return new Map(this.turnouts);
|
|
1877
|
+
}
|
|
1878
|
+
/**
|
|
1879
|
+
* Handle unsolicited turnout state updates from JMRI
|
|
1880
|
+
*/
|
|
1881
|
+
handleTurnoutUpdate(message) {
|
|
1882
|
+
const name = message.data?.name;
|
|
1883
|
+
const state = message.data?.state;
|
|
1884
|
+
if (!name || state === void 0) return;
|
|
1885
|
+
const oldState = this.turnouts.get(name);
|
|
1886
|
+
this.turnouts.set(name, state);
|
|
1887
|
+
if (oldState !== state) {
|
|
1888
|
+
this.emit("turnout:changed", name, state);
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
};
|
|
1892
|
+
|
|
1733
1893
|
// src/types/client-options.ts
|
|
1734
1894
|
var DEFAULT_CLIENT_OPTIONS = {
|
|
1735
1895
|
host: "localhost",
|
|
@@ -1805,6 +1965,7 @@ var JmriClient = class extends import_index.default {
|
|
|
1805
1965
|
this.powerManager = new PowerManager(this.wsClient);
|
|
1806
1966
|
this.rosterManager = new RosterManager(this.wsClient);
|
|
1807
1967
|
this.throttleManager = new ThrottleManager(this.wsClient);
|
|
1968
|
+
this.turnoutManager = new TurnoutManager(this.wsClient);
|
|
1808
1969
|
this.wsClient.on("connected", () => this.emit("connected"));
|
|
1809
1970
|
this.wsClient.on("disconnected", (reason) => this.emit("disconnected", reason));
|
|
1810
1971
|
this.wsClient.on(
|
|
@@ -1828,6 +1989,10 @@ var JmriClient = class extends import_index.default {
|
|
|
1828
1989
|
"power:changed",
|
|
1829
1990
|
(state) => this.emit("power:changed", state)
|
|
1830
1991
|
);
|
|
1992
|
+
this.turnoutManager.on(
|
|
1993
|
+
"turnout:changed",
|
|
1994
|
+
(name, state) => this.emit("turnout:changed", name, state)
|
|
1995
|
+
);
|
|
1831
1996
|
this.throttleManager.on(
|
|
1832
1997
|
"throttle:acquired",
|
|
1833
1998
|
(id) => this.emit("throttle:acquired", id)
|
|
@@ -1931,6 +2096,51 @@ var JmriClient = class extends import_index.default {
|
|
|
1931
2096
|
return this.rosterManager.searchRoster(query);
|
|
1932
2097
|
}
|
|
1933
2098
|
// ============================================================================
|
|
2099
|
+
// Turnout Control
|
|
2100
|
+
// ============================================================================
|
|
2101
|
+
/**
|
|
2102
|
+
* Get the current state of a turnout
|
|
2103
|
+
*/
|
|
2104
|
+
async getTurnout(name) {
|
|
2105
|
+
return this.turnoutManager.getTurnout(name);
|
|
2106
|
+
}
|
|
2107
|
+
/**
|
|
2108
|
+
* Set a turnout to the given state
|
|
2109
|
+
*/
|
|
2110
|
+
async setTurnout(name, state) {
|
|
2111
|
+
return this.turnoutManager.setTurnout(name, state);
|
|
2112
|
+
}
|
|
2113
|
+
/**
|
|
2114
|
+
* Throw a turnout (diverging route)
|
|
2115
|
+
*/
|
|
2116
|
+
async throwTurnout(name) {
|
|
2117
|
+
return this.turnoutManager.throwTurnout(name);
|
|
2118
|
+
}
|
|
2119
|
+
/**
|
|
2120
|
+
* Close a turnout (straight through / normal)
|
|
2121
|
+
*/
|
|
2122
|
+
async closeTurnout(name) {
|
|
2123
|
+
return this.turnoutManager.closeTurnout(name);
|
|
2124
|
+
}
|
|
2125
|
+
/**
|
|
2126
|
+
* List all turnouts known to JMRI
|
|
2127
|
+
*/
|
|
2128
|
+
async listTurnouts() {
|
|
2129
|
+
return this.turnoutManager.listTurnouts();
|
|
2130
|
+
}
|
|
2131
|
+
/**
|
|
2132
|
+
* Get cached turnout state without a network request
|
|
2133
|
+
*/
|
|
2134
|
+
getTurnoutState(name) {
|
|
2135
|
+
return this.turnoutManager.getTurnoutState(name);
|
|
2136
|
+
}
|
|
2137
|
+
/**
|
|
2138
|
+
* Get all cached turnout states
|
|
2139
|
+
*/
|
|
2140
|
+
getCachedTurnouts() {
|
|
2141
|
+
return this.turnoutManager.getCachedTurnouts();
|
|
2142
|
+
}
|
|
2143
|
+
// ============================================================================
|
|
1934
2144
|
// Throttle Control
|
|
1935
2145
|
// ============================================================================
|
|
1936
2146
|
/**
|
|
@@ -2030,10 +2240,11 @@ export {
|
|
|
2030
2240
|
JmriClient,
|
|
2031
2241
|
MockResponseManager,
|
|
2032
2242
|
PowerState,
|
|
2243
|
+
TurnoutState,
|
|
2033
2244
|
isThrottleFunctionKey,
|
|
2034
2245
|
isValidSpeed,
|
|
2035
2246
|
mockData,
|
|
2036
2247
|
mockResponseManager,
|
|
2037
|
-
powerStateToString
|
|
2248
|
+
powerStateToString,
|
|
2249
|
+
turnoutStateToString
|
|
2038
2250
|
};
|
|
2039
|
-
//# sourceMappingURL=jmri-client.js.map
|
package/dist/cjs/client.js
CHANGED
|
@@ -9,6 +9,7 @@ const websocket_client_js_1 = require("./core/websocket-client.js");
|
|
|
9
9
|
const power_manager_js_1 = require("./managers/power-manager.js");
|
|
10
10
|
const roster_manager_js_1 = require("./managers/roster-manager.js");
|
|
11
11
|
const throttle_manager_js_1 = require("./managers/throttle-manager.js");
|
|
12
|
+
const turnout_manager_js_1 = require("./managers/turnout-manager.js");
|
|
12
13
|
const client_options_js_1 = require("./types/client-options.js");
|
|
13
14
|
/**
|
|
14
15
|
* JMRI WebSocket Client
|
|
@@ -41,6 +42,7 @@ class JmriClient extends eventemitter3_1.EventEmitter {
|
|
|
41
42
|
this.powerManager = new power_manager_js_1.PowerManager(this.wsClient);
|
|
42
43
|
this.rosterManager = new roster_manager_js_1.RosterManager(this.wsClient);
|
|
43
44
|
this.throttleManager = new throttle_manager_js_1.ThrottleManager(this.wsClient);
|
|
45
|
+
this.turnoutManager = new turnout_manager_js_1.TurnoutManager(this.wsClient);
|
|
44
46
|
// Forward events from WebSocket client
|
|
45
47
|
this.wsClient.on('connected', () => this.emit('connected'));
|
|
46
48
|
this.wsClient.on('disconnected', (reason) => this.emit('disconnected', reason));
|
|
@@ -54,6 +56,7 @@ class JmriClient extends eventemitter3_1.EventEmitter {
|
|
|
54
56
|
this.wsClient.on('hello', (data) => this.emit('hello', data));
|
|
55
57
|
// Forward events from managers
|
|
56
58
|
this.powerManager.on('power:changed', (state) => this.emit('power:changed', state));
|
|
59
|
+
this.turnoutManager.on('turnout:changed', (name, state) => this.emit('turnout:changed', name, state));
|
|
57
60
|
this.throttleManager.on('throttle:acquired', (id) => this.emit('throttle:acquired', id));
|
|
58
61
|
this.throttleManager.on('throttle:updated', (id, data) => this.emit('throttle:updated', id, data));
|
|
59
62
|
this.throttleManager.on('throttle:released', (id) => this.emit('throttle:released', id));
|
|
@@ -148,6 +151,51 @@ class JmriClient extends eventemitter3_1.EventEmitter {
|
|
|
148
151
|
return this.rosterManager.searchRoster(query);
|
|
149
152
|
}
|
|
150
153
|
// ============================================================================
|
|
154
|
+
// Turnout Control
|
|
155
|
+
// ============================================================================
|
|
156
|
+
/**
|
|
157
|
+
* Get the current state of a turnout
|
|
158
|
+
*/
|
|
159
|
+
async getTurnout(name) {
|
|
160
|
+
return this.turnoutManager.getTurnout(name);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Set a turnout to the given state
|
|
164
|
+
*/
|
|
165
|
+
async setTurnout(name, state) {
|
|
166
|
+
return this.turnoutManager.setTurnout(name, state);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Throw a turnout (diverging route)
|
|
170
|
+
*/
|
|
171
|
+
async throwTurnout(name) {
|
|
172
|
+
return this.turnoutManager.throwTurnout(name);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Close a turnout (straight through / normal)
|
|
176
|
+
*/
|
|
177
|
+
async closeTurnout(name) {
|
|
178
|
+
return this.turnoutManager.closeTurnout(name);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* List all turnouts known to JMRI
|
|
182
|
+
*/
|
|
183
|
+
async listTurnouts() {
|
|
184
|
+
return this.turnoutManager.listTurnouts();
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Get cached turnout state without a network request
|
|
188
|
+
*/
|
|
189
|
+
getTurnoutState(name) {
|
|
190
|
+
return this.turnoutManager.getTurnoutState(name);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Get all cached turnout states
|
|
194
|
+
*/
|
|
195
|
+
getCachedTurnouts() {
|
|
196
|
+
return this.turnoutManager.getCachedTurnouts();
|
|
197
|
+
}
|
|
198
|
+
// ============================================================================
|
|
151
199
|
// Throttle Control
|
|
152
200
|
// ============================================================================
|
|
153
201
|
/**
|
|
@@ -243,4 +291,3 @@ class JmriClient extends eventemitter3_1.EventEmitter {
|
|
|
243
291
|
}
|
|
244
292
|
}
|
|
245
293
|
exports.JmriClient = JmriClient;
|
|
246
|
-
//# sourceMappingURL=client.js.map
|
package/dist/cjs/core/index.js
CHANGED
|
@@ -23,4 +23,3 @@ __exportStar(require("./connection-state-manager.js"), exports);
|
|
|
23
23
|
__exportStar(require("./reconnection-manager.js"), exports);
|
|
24
24
|
__exportStar(require("./heartbeat-manager.js"), exports);
|
|
25
25
|
__exportStar(require("./message-queue.js"), exports);
|
|
26
|
-
//# sourceMappingURL=index.js.map
|
package/dist/cjs/index.js
CHANGED
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|
* WebSocket client for JMRI with real-time updates and throttle control
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.mockData = exports.mockResponseManager = exports.MockResponseManager = exports.powerStateToString = exports.isValidSpeed = exports.isThrottleFunctionKey = exports.ConnectionState = exports.PowerState = exports.JmriClient = void 0;
|
|
7
|
+
exports.mockData = exports.mockResponseManager = exports.MockResponseManager = exports.turnoutStateToString = exports.powerStateToString = exports.isValidSpeed = exports.isThrottleFunctionKey = exports.ConnectionState = exports.TurnoutState = exports.PowerState = exports.JmriClient = void 0;
|
|
8
8
|
var client_js_1 = require("./client.js");
|
|
9
9
|
Object.defineProperty(exports, "JmriClient", { enumerable: true, get: function () { return client_js_1.JmriClient; } });
|
|
10
10
|
// Export types
|
|
11
11
|
var index_js_1 = require("./types/index.js");
|
|
12
12
|
// JMRI message types
|
|
13
13
|
Object.defineProperty(exports, "PowerState", { enumerable: true, get: function () { return index_js_1.PowerState; } });
|
|
14
|
+
Object.defineProperty(exports, "TurnoutState", { enumerable: true, get: function () { return index_js_1.TurnoutState; } });
|
|
14
15
|
// Event types
|
|
15
16
|
Object.defineProperty(exports, "ConnectionState", { enumerable: true, get: function () { return index_js_1.ConnectionState; } });
|
|
16
17
|
// Export utility functions
|
|
@@ -19,9 +20,9 @@ Object.defineProperty(exports, "isThrottleFunctionKey", { enumerable: true, get:
|
|
|
19
20
|
Object.defineProperty(exports, "isValidSpeed", { enumerable: true, get: function () { return throttle_js_1.isValidSpeed; } });
|
|
20
21
|
var jmri_messages_js_1 = require("./types/jmri-messages.js");
|
|
21
22
|
Object.defineProperty(exports, "powerStateToString", { enumerable: true, get: function () { return jmri_messages_js_1.powerStateToString; } });
|
|
23
|
+
Object.defineProperty(exports, "turnoutStateToString", { enumerable: true, get: function () { return jmri_messages_js_1.turnoutStateToString; } });
|
|
22
24
|
// Export mock system for testing and demo purposes
|
|
23
25
|
var index_js_2 = require("./mocks/index.js");
|
|
24
26
|
Object.defineProperty(exports, "MockResponseManager", { enumerable: true, get: function () { return index_js_2.MockResponseManager; } });
|
|
25
27
|
Object.defineProperty(exports, "mockResponseManager", { enumerable: true, get: function () { return index_js_2.mockResponseManager; } });
|
|
26
28
|
Object.defineProperty(exports, "mockData", { enumerable: true, get: function () { return index_js_2.mockData; } });
|
|
27
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -20,4 +20,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
20
20
|
__exportStar(require("./power-manager.js"), exports);
|
|
21
21
|
__exportStar(require("./roster-manager.js"), exports);
|
|
22
22
|
__exportStar(require("./throttle-manager.js"), exports);
|
|
23
|
-
|
|
23
|
+
__exportStar(require("./turnout-manager.js"), exports);
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Turnout (switch) manager
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.TurnoutManager = void 0;
|
|
7
|
+
const eventemitter3_1 = require("eventemitter3");
|
|
8
|
+
const jmri_messages_js_1 = require("../types/jmri-messages.js");
|
|
9
|
+
/**
|
|
10
|
+
* Manages JMRI turnout (track switch) state
|
|
11
|
+
*/
|
|
12
|
+
class TurnoutManager extends eventemitter3_1.EventEmitter {
|
|
13
|
+
constructor(client) {
|
|
14
|
+
super();
|
|
15
|
+
this.turnouts = new Map();
|
|
16
|
+
this.client = client;
|
|
17
|
+
this.client.on('update', (message) => {
|
|
18
|
+
if (message.type === 'turnout') {
|
|
19
|
+
this.handleTurnoutUpdate(message);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get the current state of a turnout.
|
|
25
|
+
* Also registers a server-side listener so subsequent changes are pushed.
|
|
26
|
+
*/
|
|
27
|
+
async getTurnout(name) {
|
|
28
|
+
const message = {
|
|
29
|
+
type: 'turnout',
|
|
30
|
+
data: { name }
|
|
31
|
+
};
|
|
32
|
+
const response = await this.client.request(message);
|
|
33
|
+
const state = response.data?.state ?? jmri_messages_js_1.TurnoutState.UNKNOWN;
|
|
34
|
+
this.turnouts.set(name, state);
|
|
35
|
+
return state;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Set a turnout to the given state
|
|
39
|
+
*/
|
|
40
|
+
async setTurnout(name, state) {
|
|
41
|
+
const message = {
|
|
42
|
+
type: 'turnout',
|
|
43
|
+
method: 'post',
|
|
44
|
+
data: { name, state }
|
|
45
|
+
};
|
|
46
|
+
await this.client.request(message);
|
|
47
|
+
const oldState = this.turnouts.get(name);
|
|
48
|
+
this.turnouts.set(name, state);
|
|
49
|
+
if (oldState !== state) {
|
|
50
|
+
this.emit('turnout:changed', name, state);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Throw a turnout (diverging route)
|
|
55
|
+
*/
|
|
56
|
+
async throwTurnout(name) {
|
|
57
|
+
return this.setTurnout(name, jmri_messages_js_1.TurnoutState.THROWN);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Close a turnout (straight through / normal)
|
|
61
|
+
*/
|
|
62
|
+
async closeTurnout(name) {
|
|
63
|
+
return this.setTurnout(name, jmri_messages_js_1.TurnoutState.CLOSED);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* List all turnouts known to JMRI
|
|
67
|
+
*/
|
|
68
|
+
async listTurnouts() {
|
|
69
|
+
const message = {
|
|
70
|
+
type: 'turnout',
|
|
71
|
+
method: 'list'
|
|
72
|
+
};
|
|
73
|
+
const response = await this.client.request(message);
|
|
74
|
+
const entries = Array.isArray(response) ? response.map((r) => r.data ?? r) : [];
|
|
75
|
+
for (const entry of entries) {
|
|
76
|
+
if (entry.name && entry.state !== undefined) {
|
|
77
|
+
this.turnouts.set(entry.name, entry.state);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return entries;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Get cached turnout state without a network request
|
|
84
|
+
*/
|
|
85
|
+
getTurnoutState(name) {
|
|
86
|
+
return this.turnouts.get(name);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Get all cached turnout states
|
|
90
|
+
*/
|
|
91
|
+
getCachedTurnouts() {
|
|
92
|
+
return new Map(this.turnouts);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Handle unsolicited turnout state updates from JMRI
|
|
96
|
+
*/
|
|
97
|
+
handleTurnoutUpdate(message) {
|
|
98
|
+
const name = message.data?.name;
|
|
99
|
+
const state = message.data?.state;
|
|
100
|
+
if (!name || state === undefined)
|
|
101
|
+
return;
|
|
102
|
+
const oldState = this.turnouts.get(name);
|
|
103
|
+
this.turnouts.set(name, state);
|
|
104
|
+
if (oldState !== state) {
|
|
105
|
+
this.emit('turnout:changed', name, state);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
exports.TurnoutManager = TurnoutManager;
|
package/dist/cjs/mocks/index.js
CHANGED
|
@@ -10,4 +10,3 @@ Object.defineProperty(exports, "mockResponseManager", { enumerable: true, get: f
|
|
|
10
10
|
// Re-export mock data for direct access if needed
|
|
11
11
|
var mock_data_js_1 = require("./mock-data.js");
|
|
12
12
|
Object.defineProperty(exports, "mockData", { enumerable: true, get: function () { return mock_data_js_1.mockData; } });
|
|
13
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -188,6 +188,13 @@ exports.mockData = {
|
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
190
|
},
|
|
191
|
+
"turnout": {
|
|
192
|
+
"list": [
|
|
193
|
+
{ "type": "turnout", "data": { "name": "LT1", "userName": "Main Diverge", "state": 2 } },
|
|
194
|
+
{ "type": "turnout", "data": { "name": "LT2", "userName": "Yard Lead", "state": 2 } },
|
|
195
|
+
{ "type": "turnout", "data": { "name": "LT3", "userName": "Siding Entry", "state": 4 } }
|
|
196
|
+
]
|
|
197
|
+
},
|
|
191
198
|
"ping": {
|
|
192
199
|
"type": "ping"
|
|
193
200
|
},
|
|
@@ -221,4 +228,3 @@ exports.mockData = {
|
|
|
221
228
|
}
|
|
222
229
|
}
|
|
223
230
|
};
|
|
224
|
-
//# sourceMappingURL=mock-data.js.map
|
|
@@ -13,6 +13,11 @@ const mock_data_js_1 = require("./mock-data.js");
|
|
|
13
13
|
class MockResponseManager {
|
|
14
14
|
constructor(options = {}) {
|
|
15
15
|
this.throttles = new Map();
|
|
16
|
+
this.turnouts = new Map([
|
|
17
|
+
['LT1', jmri_messages_js_1.TurnoutState.CLOSED],
|
|
18
|
+
['LT2', jmri_messages_js_1.TurnoutState.CLOSED],
|
|
19
|
+
['LT3', jmri_messages_js_1.TurnoutState.THROWN]
|
|
20
|
+
]);
|
|
16
21
|
this.responseDelay = options.responseDelay ?? 50;
|
|
17
22
|
this.powerState = options.initialPowerState ?? jmri_messages_js_1.PowerState.OFF;
|
|
18
23
|
}
|
|
@@ -34,6 +39,8 @@ class MockResponseManager {
|
|
|
34
39
|
return this.getRosterResponse(message);
|
|
35
40
|
case 'throttle':
|
|
36
41
|
return this.getThrottleResponse(message);
|
|
42
|
+
case 'turnout':
|
|
43
|
+
return this.getTurnoutResponse(message);
|
|
37
44
|
case 'ping':
|
|
38
45
|
return this.getPingResponse();
|
|
39
46
|
case 'goodbye':
|
|
@@ -160,6 +167,26 @@ class MockResponseManager {
|
|
|
160
167
|
data: {}
|
|
161
168
|
};
|
|
162
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* Get turnout response
|
|
172
|
+
*/
|
|
173
|
+
getTurnoutResponse(message) {
|
|
174
|
+
// List all turnouts
|
|
175
|
+
if (message.method === 'list') {
|
|
176
|
+
return JSON.parse(JSON.stringify(mock_data_js_1.mockData.turnout.list));
|
|
177
|
+
}
|
|
178
|
+
const name = message.data?.name;
|
|
179
|
+
if (!name) {
|
|
180
|
+
return { type: 'turnout', data: { name: '', state: jmri_messages_js_1.TurnoutState.UNKNOWN } };
|
|
181
|
+
}
|
|
182
|
+
// Set turnout state
|
|
183
|
+
if (message.method === 'post' && message.data?.state !== undefined) {
|
|
184
|
+
this.turnouts.set(name, message.data.state);
|
|
185
|
+
}
|
|
186
|
+
// Get or confirm current state
|
|
187
|
+
const state = this.turnouts.get(name) ?? jmri_messages_js_1.TurnoutState.UNKNOWN;
|
|
188
|
+
return { type: 'turnout', data: { name, state } };
|
|
189
|
+
}
|
|
163
190
|
/**
|
|
164
191
|
* Get ping response (pong)
|
|
165
192
|
*/
|
|
@@ -190,12 +217,23 @@ class MockResponseManager {
|
|
|
190
217
|
getThrottles() {
|
|
191
218
|
return this.throttles;
|
|
192
219
|
}
|
|
220
|
+
/**
|
|
221
|
+
* Get all turnout states (for testing)
|
|
222
|
+
*/
|
|
223
|
+
getTurnouts() {
|
|
224
|
+
return this.turnouts;
|
|
225
|
+
}
|
|
193
226
|
/**
|
|
194
227
|
* Reset all state (for testing)
|
|
195
228
|
*/
|
|
196
229
|
reset() {
|
|
197
230
|
this.powerState = jmri_messages_js_1.PowerState.OFF;
|
|
198
231
|
this.throttles.clear();
|
|
232
|
+
this.turnouts = new Map([
|
|
233
|
+
['LT1', jmri_messages_js_1.TurnoutState.CLOSED],
|
|
234
|
+
['LT2', jmri_messages_js_1.TurnoutState.CLOSED],
|
|
235
|
+
['LT3', jmri_messages_js_1.TurnoutState.THROWN]
|
|
236
|
+
]);
|
|
199
237
|
}
|
|
200
238
|
/**
|
|
201
239
|
* Delay helper
|
|
@@ -209,4 +247,3 @@ exports.MockResponseManager = MockResponseManager;
|
|
|
209
247
|
* Singleton instance for shared use across tests
|
|
210
248
|
*/
|
|
211
249
|
exports.mockResponseManager = new MockResponseManager({ responseDelay: 0 });
|
|
212
|
-
//# sourceMappingURL=mock-response-manager.js.map
|