@robdobsn/raftjs 1.1.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/.editorconfig +14 -0
- package/.gitattributes +11 -0
- package/.nvmrc +1 -0
- package/LICENSE +22 -0
- package/README.md +11 -0
- package/TODO.md +1 -0
- package/dist/RaftAttributeHandler.d.ts +12 -0
- package/dist/RaftAttributeHandler.js +241 -0
- package/dist/RaftAttributeHandler.js.map +1 -0
- package/dist/RaftChannel.d.ts +18 -0
- package/dist/RaftChannel.js +12 -0
- package/dist/RaftChannel.js.map +1 -0
- package/dist/RaftChannelWebBLE.d.ts +38 -0
- package/dist/RaftChannelWebBLE.js +274 -0
- package/dist/RaftChannelWebBLE.js.map +1 -0
- package/dist/RaftChannelWebSerial.d.ts +37 -0
- package/dist/RaftChannelWebSerial.js +319 -0
- package/dist/RaftChannelWebSerial.js.map +1 -0
- package/dist/RaftChannelWebSocket.d.ts +28 -0
- package/dist/RaftChannelWebSocket.js +197 -0
- package/dist/RaftChannelWebSocket.js.map +1 -0
- package/dist/RaftCommsStats.d.ts +39 -0
- package/dist/RaftCommsStats.js +128 -0
- package/dist/RaftCommsStats.js.map +1 -0
- package/dist/RaftConnEvents.d.ts +31 -0
- package/dist/RaftConnEvents.js +44 -0
- package/dist/RaftConnEvents.js.map +1 -0
- package/dist/RaftConnector.d.ts +242 -0
- package/dist/RaftConnector.js +613 -0
- package/dist/RaftConnector.js.map +1 -0
- package/dist/RaftCustomAttrHandler.d.ts +4 -0
- package/dist/RaftCustomAttrHandler.js +50 -0
- package/dist/RaftCustomAttrHandler.js.map +1 -0
- package/dist/RaftDeviceInfo.d.ts +64 -0
- package/dist/RaftDeviceInfo.js +36 -0
- package/dist/RaftDeviceInfo.js.map +1 -0
- package/dist/RaftDeviceManager.d.ts +37 -0
- package/dist/RaftDeviceManager.js +450 -0
- package/dist/RaftDeviceManager.js.map +1 -0
- package/dist/RaftDeviceMsg.d.ts +9 -0
- package/dist/RaftDeviceMsg.js +11 -0
- package/dist/RaftDeviceMsg.js.map +1 -0
- package/dist/RaftDeviceStates.d.ts +33 -0
- package/dist/RaftDeviceStates.js +60 -0
- package/dist/RaftDeviceStates.js.map +1 -0
- package/dist/RaftFileHandler.d.ts +52 -0
- package/dist/RaftFileHandler.js +502 -0
- package/dist/RaftFileHandler.js.map +1 -0
- package/dist/RaftLog.d.ts +22 -0
- package/dist/RaftLog.js +63 -0
- package/dist/RaftLog.js.map +1 -0
- package/dist/RaftMiniHDLC.d.ts +18 -0
- package/dist/RaftMiniHDLC.js +383 -0
- package/dist/RaftMiniHDLC.js.map +1 -0
- package/dist/RaftMsgHandler.d.ts +57 -0
- package/dist/RaftMsgHandler.js +480 -0
- package/dist/RaftMsgHandler.js.map +1 -0
- package/dist/RaftMsgTrackInfo.d.ts +17 -0
- package/dist/RaftMsgTrackInfo.js +42 -0
- package/dist/RaftMsgTrackInfo.js.map +1 -0
- package/dist/RaftProtocolDefs.d.ts +30 -0
- package/dist/RaftProtocolDefs.js +48 -0
- package/dist/RaftProtocolDefs.js.map +1 -0
- package/dist/RaftStreamHandler.d.ts +38 -0
- package/dist/RaftStreamHandler.js +257 -0
- package/dist/RaftStreamHandler.js.map +1 -0
- package/dist/RaftSystemType.d.ts +21 -0
- package/dist/RaftSystemType.js +3 -0
- package/dist/RaftSystemType.js.map +1 -0
- package/dist/RaftSystemUtils.d.ts +136 -0
- package/dist/RaftSystemUtils.js +410 -0
- package/dist/RaftSystemUtils.js.map +1 -0
- package/dist/RaftTypes.d.ts +184 -0
- package/dist/RaftTypes.js +157 -0
- package/dist/RaftTypes.js.map +1 -0
- package/dist/RaftUpdateEvents.d.ts +33 -0
- package/dist/RaftUpdateEvents.js +46 -0
- package/dist/RaftUpdateEvents.js.map +1 -0
- package/dist/RaftUpdateManager.d.ts +61 -0
- package/dist/RaftUpdateManager.js +618 -0
- package/dist/RaftUpdateManager.js.map +1 -0
- package/dist/RaftUtils.d.ts +125 -0
- package/dist/RaftUtils.js +454 -0
- package/dist/RaftUtils.js.map +1 -0
- package/dist/RaftWifiTypes.d.ts +23 -0
- package/dist/RaftWifiTypes.js +43 -0
- package/dist/RaftWifiTypes.js.map +1 -0
- package/dist/TestDataGen.d.ts +7 -0
- package/dist/TestDataGen.js +133 -0
- package/dist/TestDataGen.js.map +1 -0
- package/dist/main.d.ts +18 -0
- package/dist/main.js +42 -0
- package/dist/main.js.map +1 -0
- package/eslint.config.mjs +33 -0
- package/examples/dashboard/package.json +39 -0
- package/examples/dashboard/src/ConnManager.ts +86 -0
- package/examples/dashboard/src/Main.tsx +100 -0
- package/examples/dashboard/src/StatusScreen.tsx +72 -0
- package/examples/dashboard/src/SystemTypeCog/CogStateInfo.ts +144 -0
- package/examples/dashboard/src/SystemTypeCog/SystemTypeCog.ts +77 -0
- package/examples/dashboard/src/SystemTypeMarty/RICAddOn.ts +70 -0
- package/examples/dashboard/src/SystemTypeMarty/RICAddOnBase.ts +33 -0
- package/examples/dashboard/src/SystemTypeMarty/RICAddOnManager.ts +342 -0
- package/examples/dashboard/src/SystemTypeMarty/RICCommsStats.ts +170 -0
- package/examples/dashboard/src/SystemTypeMarty/RICHWElem.ts +123 -0
- package/examples/dashboard/src/SystemTypeMarty/RICLEDPatternChecker.ts +207 -0
- package/examples/dashboard/src/SystemTypeMarty/RICROSSerial.ts +464 -0
- package/examples/dashboard/src/SystemTypeMarty/RICServoFaultDetector.ts +146 -0
- package/examples/dashboard/src/SystemTypeMarty/RICStateInfo.ts +32 -0
- package/examples/dashboard/src/SystemTypeMarty/RICSystemUtils.ts +371 -0
- package/examples/dashboard/src/SystemTypeMarty/RICTypes.ts +20 -0
- package/examples/dashboard/src/SystemTypeMarty/SystemTypeMarty.ts +113 -0
- package/examples/dashboard/src/index.html +15 -0
- package/examples/dashboard/src/index.tsx +15 -0
- package/examples/dashboard/src/styles.css +122 -0
- package/examples/dashboard/tsconfig.json +18 -0
- package/jest.config.js +11 -0
- package/package.json +50 -0
- package/src/RaftAttributeHandler.ts +289 -0
- package/src/RaftChannel.ts +30 -0
- package/src/RaftChannelWebBLE.ts +342 -0
- package/src/RaftChannelWebSerial.ts +408 -0
- package/src/RaftChannelWebSocket.ts +245 -0
- package/src/RaftCommsStats.ts +142 -0
- package/src/RaftConnEvents.ts +46 -0
- package/src/RaftConnector.ts +745 -0
- package/src/RaftCustomAttrHandler.ts +54 -0
- package/src/RaftDeviceInfo.ts +104 -0
- package/src/RaftDeviceManager.ts +542 -0
- package/src/RaftDeviceMsg.ts +20 -0
- package/src/RaftDeviceStates.ts +89 -0
- package/src/RaftFileHandler.ts +668 -0
- package/src/RaftLog.ts +70 -0
- package/src/RaftMiniHDLC.ts +396 -0
- package/src/RaftMsgHandler.ts +778 -0
- package/src/RaftMsgTrackInfo.ts +51 -0
- package/src/RaftProtocolDefs.ts +46 -0
- package/src/RaftStreamHandler.ts +328 -0
- package/src/RaftSystemType.ts +25 -0
- package/src/RaftSystemUtils.ts +487 -0
- package/src/RaftTypes.ts +250 -0
- package/src/RaftUpdateEvents.ts +48 -0
- package/src/RaftUpdateManager.ts +778 -0
- package/src/RaftUtils.ts +484 -0
- package/src/RaftWifiTypes.ts +36 -0
- package/src/TestDataGen.ts +157 -0
- package/src/main.ts +28 -0
- package/testdata/TestDeviceTypeRecs.json +492 -0
- package/tsconfig.json +27 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
3
|
+
//
|
|
4
|
+
// RaftCustomAttrHandler
|
|
5
|
+
// Custom attribute handler for Raft devices
|
|
6
|
+
//
|
|
7
|
+
// Rob Dobson (C) 2024
|
|
8
|
+
//
|
|
9
|
+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
class CustomAttrHandler {
|
|
12
|
+
handleAttr(pollRespMetadata, msgBuffer, msgBufIdx) {
|
|
13
|
+
// Number of bytes in the each message
|
|
14
|
+
const numMsgBytes = pollRespMetadata.b;
|
|
15
|
+
// Create a vector for each attribute in the metadata
|
|
16
|
+
let attrValueVecs = [];
|
|
17
|
+
// Reference to each vector by attribute name
|
|
18
|
+
let attrValues = {};
|
|
19
|
+
// Add attributes to the vector
|
|
20
|
+
for (let attrIdx = 0; attrIdx < pollRespMetadata.a.length; attrIdx++) {
|
|
21
|
+
attrValueVecs.push([]);
|
|
22
|
+
attrValues[pollRespMetadata.a[attrIdx].n] = attrValueVecs[attrIdx];
|
|
23
|
+
}
|
|
24
|
+
// Custom code for each device type
|
|
25
|
+
if (pollRespMetadata.c.n === "max30101_fifo") {
|
|
26
|
+
// Hex dump msgBuffer
|
|
27
|
+
// console.log(`CustomAttrHandler handleAttr ${pollRespMetadata.c!.n} msgBuffer: ${msgBuffer.toString('hex')}`);
|
|
28
|
+
let buf = msgBuffer.slice(msgBufIdx);
|
|
29
|
+
if (buf.length < numMsgBytes) {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
// Generated code ...
|
|
33
|
+
let N = (buf[0] + 32 - buf[2]) % 32;
|
|
34
|
+
let k = 3;
|
|
35
|
+
let i = 0;
|
|
36
|
+
while (i < N) {
|
|
37
|
+
attrValues['Red'].push(0);
|
|
38
|
+
attrValues['Red'][attrValues['Red'].length - 1] = (buf[k] << 16) | (buf[k + 1] << 8) | buf[k + 2];
|
|
39
|
+
attrValues['IR'].push(0);
|
|
40
|
+
attrValues['IR'][attrValues['IR'].length - 1] = (buf[k + 3] << 16) | (buf[k + 4] << 8) | buf[k + 5];
|
|
41
|
+
k += 6;
|
|
42
|
+
i++;
|
|
43
|
+
;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return attrValueVecs;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.default = CustomAttrHandler;
|
|
50
|
+
//# sourceMappingURL=RaftCustomAttrHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RaftCustomAttrHandler.js","sourceRoot":"","sources":["../src/RaftCustomAttrHandler.ts"],"names":[],"mappings":";AAAA,iHAAiH;AACjH,EAAE;AACF,wBAAwB;AACxB,4CAA4C;AAC5C,EAAE;AACF,sBAAsB;AACtB,EAAE;AACF,iHAAiH;;AAIjH,MAAqB,iBAAiB;IAE3B,UAAU,CAAC,gBAA4C,EAAE,SAAiB,EAAE,SAAiB;QAEhG,sCAAsC;QACtC,MAAM,WAAW,GAAG,gBAAgB,CAAC,CAAC,CAAC;QAEvC,qDAAqD;QACrD,IAAI,aAAa,GAAS,EAAE,CAAC;QAE7B,6CAA6C;QAC7C,IAAI,UAAU,GAAgC,EAAE,CAAC;QAEjD,+BAA+B;QAC/B,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,gBAAgB,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC;YACnE,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACvB,UAAU,CAAC,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;QACvE,CAAC;QAED,mCAAmC;QACnC,IAAI,gBAAgB,CAAC,CAAE,CAAC,CAAC,KAAK,eAAe,EAAE,CAAC;YAC5C,qBAAqB;YACrB,iHAAiH;YACjH,IAAI,GAAG,GAAG,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YACrC,IAAI,GAAG,CAAC,MAAM,GAAG,WAAW,EAAE,CAAC;gBAC3B,OAAO,EAAE,CAAC;YACd,CAAC;YAED,qBAAqB;YACrB,IAAI,CAAC,GAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAC,EAAE,GAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAC,EAAE,CAAC;YAC5B,IAAI,CAAC,GAAC,CAAC,CAAC;YACR,IAAI,CAAC,GAAC,CAAC,CAAC;YACR,OAAO,CAAC,GAAC,CAAC,EAAE,CAAC;gBACT,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAAC,UAAU,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,GAAC,CAAC,CAAC,GAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAE,EAAE,CAAC,GAAC,CAAC,GAAG,CAAC,CAAC,GAAC,CAAC,CAAC,IAAE,CAAC,CAAC,GAAC,GAAG,CAAC,CAAC,GAAC,CAAC,CAAC,CAAC;gBAC9G,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAAC,UAAU,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,MAAM,GAAC,CAAC,CAAC,GAAE,CAAC,GAAG,CAAC,CAAC,GAAC,CAAC,CAAC,IAAE,EAAE,CAAC,GAAC,CAAC,GAAG,CAAC,CAAC,GAAC,CAAC,CAAC,IAAE,CAAC,CAAC,GAAC,GAAG,CAAC,CAAC,GAAC,CAAC,CAAC,CAAC;gBAC7G,CAAC,IAAE,CAAC,CAAC;gBACL,CAAC,EAAE,CAAC;gBACJ,CAAC;YACL,CAAC;QACL,CAAC;QACD,OAAO,aAAa,CAAC;IACzB,CAAC;CACJ;AA1CD,oCA0CC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export declare function getAttrTypeBits(attrType: string): number;
|
|
2
|
+
export declare function isAttrTypeSigned(attrType: string): boolean;
|
|
3
|
+
export declare function decodeAttrUnitsEncoding(unitsEncoding: string): string;
|
|
4
|
+
export interface DeviceTypeAttribute {
|
|
5
|
+
n: string;
|
|
6
|
+
t: string;
|
|
7
|
+
at?: number;
|
|
8
|
+
u?: string;
|
|
9
|
+
r?: number[];
|
|
10
|
+
x?: number;
|
|
11
|
+
m?: number | string;
|
|
12
|
+
s?: number;
|
|
13
|
+
sb?: number;
|
|
14
|
+
ss?: number;
|
|
15
|
+
d?: number;
|
|
16
|
+
a?: number;
|
|
17
|
+
f?: string;
|
|
18
|
+
o?: string;
|
|
19
|
+
v?: boolean | number;
|
|
20
|
+
vs?: boolean | number;
|
|
21
|
+
vf?: boolean | number;
|
|
22
|
+
}
|
|
23
|
+
export interface CustomFunctionDefinition {
|
|
24
|
+
n: string;
|
|
25
|
+
c: string;
|
|
26
|
+
}
|
|
27
|
+
export interface DeviceTypePollRespMetadata {
|
|
28
|
+
b: number;
|
|
29
|
+
a: DeviceTypeAttribute[];
|
|
30
|
+
c?: CustomFunctionDefinition;
|
|
31
|
+
us?: number;
|
|
32
|
+
}
|
|
33
|
+
export interface DeviceTypeAction {
|
|
34
|
+
n: string;
|
|
35
|
+
t?: string;
|
|
36
|
+
w: string;
|
|
37
|
+
r?: number[];
|
|
38
|
+
f?: string;
|
|
39
|
+
NX?: number;
|
|
40
|
+
NY?: number;
|
|
41
|
+
concat?: boolean;
|
|
42
|
+
d?: number;
|
|
43
|
+
}
|
|
44
|
+
export interface DeviceTypeInfo {
|
|
45
|
+
name: string;
|
|
46
|
+
desc: string;
|
|
47
|
+
manu: string;
|
|
48
|
+
type: string;
|
|
49
|
+
resp?: DeviceTypePollRespMetadata;
|
|
50
|
+
actions?: DeviceTypeAction[];
|
|
51
|
+
}
|
|
52
|
+
export interface DeviceTypeInfoRecs {
|
|
53
|
+
[devType: string]: DeviceTypeInfo;
|
|
54
|
+
}
|
|
55
|
+
export interface DeviceTypeInfoTestJsonRec {
|
|
56
|
+
addresses?: string;
|
|
57
|
+
devInfoJson: DeviceTypeInfo;
|
|
58
|
+
}
|
|
59
|
+
export interface DeviceTypeInfoTestJsonElem {
|
|
60
|
+
[devType: string]: DeviceTypeInfoTestJsonRec;
|
|
61
|
+
}
|
|
62
|
+
export interface DeviceTypeInfoTestJsonFile {
|
|
63
|
+
devTypes: DeviceTypeInfoTestJsonElem;
|
|
64
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
3
|
+
//
|
|
4
|
+
// RaftDeviceInfo
|
|
5
|
+
// Device information for Raft devices
|
|
6
|
+
//
|
|
7
|
+
// Rob Dobson (C) 2024
|
|
8
|
+
//
|
|
9
|
+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.getAttrTypeBits = getAttrTypeBits;
|
|
12
|
+
exports.isAttrTypeSigned = isAttrTypeSigned;
|
|
13
|
+
exports.decodeAttrUnitsEncoding = decodeAttrUnitsEncoding;
|
|
14
|
+
const attrTypeBits = {
|
|
15
|
+
"c": 8, "b": 8, "B": 8, "?": 8,
|
|
16
|
+
"h": 16, "H": 16, ">h": 16, "<h": 16, ">H": 16, "<H": 16,
|
|
17
|
+
"i": 32, "I": 32, ">i": 32, "<i": 32, ">I": 32, "<I": 32, "l": 32, "L": 32, ">l": 32, "<l": 32, ">L": 32, "<L": 32,
|
|
18
|
+
"q": 64, "Q": 64, ">q": 64, "<q": 64, ">Q": 64, "<Q": 64,
|
|
19
|
+
"f": 32, ">f": 32, "<f": 32,
|
|
20
|
+
"d": 64, ">d": 64, "<d": 64,
|
|
21
|
+
};
|
|
22
|
+
function getAttrTypeBits(attrType) {
|
|
23
|
+
if (attrType in attrTypeBits) {
|
|
24
|
+
return attrTypeBits[attrType];
|
|
25
|
+
}
|
|
26
|
+
return 8;
|
|
27
|
+
}
|
|
28
|
+
function isAttrTypeSigned(attrType) {
|
|
29
|
+
const attrStr = attrType.charAt(0) === ">" || attrType.charAt(0) === "<" ? attrType.slice(1).charAt(0) : attrType.charAt(0);
|
|
30
|
+
return attrStr === "b" || attrStr === "h" || attrStr === "i" || attrStr === "l" || attrStr === "q";
|
|
31
|
+
}
|
|
32
|
+
function decodeAttrUnitsEncoding(unitsEncoding) {
|
|
33
|
+
// Replace instances of HTML encoded chars like ° with the actual char
|
|
34
|
+
return unitsEncoding.replace(/°/g, "°");
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=RaftDeviceInfo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RaftDeviceInfo.js","sourceRoot":"","sources":["../src/RaftDeviceInfo.ts"],"names":[],"mappings":";AAAA,iHAAiH;AACjH,EAAE;AACF,iBAAiB;AACjB,sCAAsC;AACtC,EAAE;AACF,sBAAsB;AACtB,EAAE;AACF,iHAAiH;;AAWjH,0CAKC;AAED,4CAGC;AAED,0DAGC;AAxBD,MAAM,YAAY,GAA8B;IAC5C,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC;IAC9B,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE;IACxD,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE;IAClH,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE;IACxD,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE;IAC3B,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE;CAC1B,CAAC;AAEN,SAAgB,eAAe,CAAC,QAAgB;IAC5C,IAAI,QAAQ,IAAI,YAAY,EAAE,CAAC;QAC3B,OAAO,YAAY,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,CAAC,CAAC;AACb,CAAC;AAED,SAAgB,gBAAgB,CAAC,QAAgB;IAC7C,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC5H,OAAO,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,GAAG,CAAC;AACvG,CAAC;AAED,SAAgB,uBAAuB,CAAC,aAAqB;IACzD,0EAA0E;IAC1E,OAAO,aAAa,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { DeviceAttributeState, DevicesState, DeviceState } from "./RaftDeviceStates";
|
|
2
|
+
import { DeviceTypeAction } from "./RaftDeviceInfo";
|
|
3
|
+
import { DataType } from 'python-struct';
|
|
4
|
+
export declare class DeviceManager {
|
|
5
|
+
private static _instance;
|
|
6
|
+
private _maxDatapointsToStore;
|
|
7
|
+
private _attributeHandler;
|
|
8
|
+
private _serverAddressPrefix;
|
|
9
|
+
private _urlPrefix;
|
|
10
|
+
private _devicesState;
|
|
11
|
+
private _callbackNewDevice;
|
|
12
|
+
private _callbackNewDeviceAttribute;
|
|
13
|
+
private _callbackNewAttributeData;
|
|
14
|
+
private _lastStateUpdate;
|
|
15
|
+
private MAX_TIME_BETWEEN_STATE_UPDATES_MS;
|
|
16
|
+
private _websocket;
|
|
17
|
+
static getInstance(): DeviceManager;
|
|
18
|
+
getDevicesState(): DevicesState;
|
|
19
|
+
getDeviceState(deviceKey: string): DeviceState;
|
|
20
|
+
private _cachedDeviceTypeRecs;
|
|
21
|
+
private _testDeviceTypeRecs;
|
|
22
|
+
private _testDataGen;
|
|
23
|
+
private constructor();
|
|
24
|
+
sendCommand(cmd: string): Promise<boolean>;
|
|
25
|
+
init(): Promise<boolean>;
|
|
26
|
+
private connectWebSocket;
|
|
27
|
+
onNewDevice(callback: (deviceKey: string, state: DeviceState) => void): void;
|
|
28
|
+
onNewDeviceAttribute(callback: (deviceKey: string, attrState: DeviceAttributeState) => void): void;
|
|
29
|
+
onNewAttributeData(callback: (deviceKey: string, attrState: DeviceAttributeState) => void): void;
|
|
30
|
+
setFriendlyName(friendlyName: string): Promise<void>;
|
|
31
|
+
private handleClientMsgJson;
|
|
32
|
+
private processStateCallback;
|
|
33
|
+
private getDeviceTypeInfo;
|
|
34
|
+
sendAction(deviceKey: string, action: DeviceTypeAction, data: DataType[]): void;
|
|
35
|
+
sendCompoundAction(deviceKey: string, action: DeviceTypeAction, data: DataType[][]): void;
|
|
36
|
+
private hexToBytes;
|
|
37
|
+
}
|
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
3
|
+
//
|
|
4
|
+
// RaftDeviceManager
|
|
5
|
+
// Device manager for Raft devices
|
|
6
|
+
//
|
|
7
|
+
// Rob Dobson (C) 2024
|
|
8
|
+
//
|
|
9
|
+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.DeviceManager = void 0;
|
|
12
|
+
const tslib_1 = require("tslib");
|
|
13
|
+
const RaftDeviceStates_1 = require("./RaftDeviceStates");
|
|
14
|
+
const python_struct_1 = tslib_1.__importDefault(require("python-struct"));
|
|
15
|
+
const TestDataGen_1 = tslib_1.__importDefault(require("./TestDataGen"));
|
|
16
|
+
const RaftAttributeHandler_1 = tslib_1.__importDefault(require("./RaftAttributeHandler"));
|
|
17
|
+
let testingDeviceTypeRecsConditionalLoadPromise = null;
|
|
18
|
+
if (process.env.TEST_DATA) {
|
|
19
|
+
testingDeviceTypeRecsConditionalLoadPromise = Promise.resolve().then(() => tslib_1.__importStar(require('../testdata/TestDeviceTypeRecs.json')));
|
|
20
|
+
}
|
|
21
|
+
class DeviceManager {
|
|
22
|
+
// Get instance
|
|
23
|
+
static getInstance() {
|
|
24
|
+
if (!DeviceManager._instance) {
|
|
25
|
+
DeviceManager._instance = new DeviceManager();
|
|
26
|
+
}
|
|
27
|
+
return DeviceManager._instance;
|
|
28
|
+
}
|
|
29
|
+
getDevicesState() {
|
|
30
|
+
return this._devicesState;
|
|
31
|
+
}
|
|
32
|
+
getDeviceState(deviceKey) {
|
|
33
|
+
return this._devicesState[deviceKey];
|
|
34
|
+
}
|
|
35
|
+
// Constructor
|
|
36
|
+
constructor() {
|
|
37
|
+
// Max data points to store
|
|
38
|
+
this._maxDatapointsToStore = 1000;
|
|
39
|
+
// Attribute handler
|
|
40
|
+
this._attributeHandler = new RaftAttributeHandler_1.default();
|
|
41
|
+
// Server address
|
|
42
|
+
this._serverAddressPrefix = "";
|
|
43
|
+
// URL prefix
|
|
44
|
+
this._urlPrefix = "/api";
|
|
45
|
+
// Devices state
|
|
46
|
+
this._devicesState = new RaftDeviceStates_1.DevicesState();
|
|
47
|
+
// Device callbacks
|
|
48
|
+
this._callbackNewDevice = null;
|
|
49
|
+
this._callbackNewDeviceAttribute = null;
|
|
50
|
+
this._callbackNewAttributeData = null;
|
|
51
|
+
// Last time we got a state update
|
|
52
|
+
this._lastStateUpdate = 0;
|
|
53
|
+
this.MAX_TIME_BETWEEN_STATE_UPDATES_MS = 60000;
|
|
54
|
+
// Websocket
|
|
55
|
+
this._websocket = null;
|
|
56
|
+
// Cached device type data
|
|
57
|
+
this._cachedDeviceTypeRecs = {};
|
|
58
|
+
// Test device type data
|
|
59
|
+
this._testDeviceTypeRecs = null;
|
|
60
|
+
this._testDataGen = new TestDataGen_1.default();
|
|
61
|
+
// Check if test mode
|
|
62
|
+
// if (window.location.hostname === "localhost") {
|
|
63
|
+
if (process.env.TEST_DATA) {
|
|
64
|
+
this._testDataGen.start((msg) => {
|
|
65
|
+
this.handleClientMsgJson(msg);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
////////////////////////////////////////////////////////////////////////////
|
|
70
|
+
// Send REST commands
|
|
71
|
+
////////////////////////////////////////////////////////////////////////////
|
|
72
|
+
async sendCommand(cmd) {
|
|
73
|
+
try {
|
|
74
|
+
const sendCommandResponse = await fetch(this._serverAddressPrefix + this._urlPrefix + cmd);
|
|
75
|
+
if (!sendCommandResponse.ok) {
|
|
76
|
+
console.warn(`DeviceManager sendCommand response not ok ${sendCommandResponse.status}`);
|
|
77
|
+
}
|
|
78
|
+
return sendCommandResponse.ok;
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
console.warn(`DeviceManager sendCommand error ${error}`);
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
////////////////////////////////////////////////////////////////////////////
|
|
86
|
+
// Init
|
|
87
|
+
////////////////////////////////////////////////////////////////////////////
|
|
88
|
+
async init() {
|
|
89
|
+
// Check if already initialized
|
|
90
|
+
if (this._websocket) {
|
|
91
|
+
console.warn(`DeviceManager init already initialized`);
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
// console.log(`DeviceManager init - first time`)
|
|
95
|
+
// Conditionally load the device type records
|
|
96
|
+
if (testingDeviceTypeRecsConditionalLoadPromise) {
|
|
97
|
+
testingDeviceTypeRecsConditionalLoadPromise.then((jsonData) => {
|
|
98
|
+
this._testDeviceTypeRecs = jsonData;
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
// Websocket if not in test mode
|
|
102
|
+
if (!process.env.TEST_DATA) {
|
|
103
|
+
// Open websocket
|
|
104
|
+
const rslt = await this.connectWebSocket();
|
|
105
|
+
// Start timer to check for websocket reconnection
|
|
106
|
+
setInterval(async () => {
|
|
107
|
+
var _a;
|
|
108
|
+
if (!this._websocket) {
|
|
109
|
+
console.log(`DeviceManager init - reconnecting websocket`);
|
|
110
|
+
await this.connectWebSocket();
|
|
111
|
+
}
|
|
112
|
+
else if ((Date.now() - this._lastStateUpdate) > this.MAX_TIME_BETWEEN_STATE_UPDATES_MS) {
|
|
113
|
+
const inactiveTimeSecs = ((Date.now() - this._lastStateUpdate) / 1000).toFixed(1);
|
|
114
|
+
if (this._websocket) {
|
|
115
|
+
console.log(`DeviceManager init - closing websocket due to ${inactiveTimeSecs}s inactivity`);
|
|
116
|
+
this._websocket.close();
|
|
117
|
+
this._websocket = null;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
console.log(`websocket state ${(_a = this._websocket) === null || _a === void 0 ? void 0 : _a.readyState}`);
|
|
121
|
+
}, 5000);
|
|
122
|
+
return rslt;
|
|
123
|
+
}
|
|
124
|
+
// Test mode
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
////////////////////////////////////////////////////////////////////////////
|
|
128
|
+
// Open websocket
|
|
129
|
+
////////////////////////////////////////////////////////////////////////////
|
|
130
|
+
async connectWebSocket() {
|
|
131
|
+
// Open a websocket to the server
|
|
132
|
+
try {
|
|
133
|
+
console.log(`DeviceManager init location.origin ${window.location.origin} ${window.location.protocol} ${window.location.host} ${window.location.hostname} ${window.location.port} ${window.location.pathname} ${window.location.search} ${window.location.hash}`);
|
|
134
|
+
let webSocketURL = this._serverAddressPrefix;
|
|
135
|
+
if (webSocketURL.startsWith("http")) {
|
|
136
|
+
webSocketURL = webSocketURL.replace(/^http/, 'ws');
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
webSocketURL = window.location.origin.replace(/^http/, 'ws');
|
|
140
|
+
}
|
|
141
|
+
webSocketURL += "/devjson";
|
|
142
|
+
console.log(`DeviceManager init opening websocket ${webSocketURL}`);
|
|
143
|
+
this._websocket = new WebSocket(webSocketURL);
|
|
144
|
+
if (!this._websocket) {
|
|
145
|
+
console.error("DeviceManager init unable to create websocket");
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
this._websocket.binaryType = "arraybuffer";
|
|
149
|
+
this._lastStateUpdate = Date.now();
|
|
150
|
+
this._websocket.onopen = () => {
|
|
151
|
+
// Debug
|
|
152
|
+
console.log(`DeviceManager init websocket opened to ${webSocketURL}`);
|
|
153
|
+
// Send subscription request messages after a short delay
|
|
154
|
+
setTimeout(() => {
|
|
155
|
+
// Subscribe to device messages
|
|
156
|
+
const subscribeName = "devices";
|
|
157
|
+
console.log(`DeviceManager init subscribing to ${subscribeName}`);
|
|
158
|
+
if (this._websocket) {
|
|
159
|
+
this._websocket.send(JSON.stringify({
|
|
160
|
+
cmdName: "subscription",
|
|
161
|
+
action: "update",
|
|
162
|
+
pubRecs: [
|
|
163
|
+
{ name: subscribeName, msgID: subscribeName, rateHz: 0.1 },
|
|
164
|
+
]
|
|
165
|
+
}));
|
|
166
|
+
}
|
|
167
|
+
}, 1000);
|
|
168
|
+
};
|
|
169
|
+
this._websocket.onmessage = (event) => {
|
|
170
|
+
this.handleClientMsgJson(event.data);
|
|
171
|
+
};
|
|
172
|
+
this._websocket.onclose = () => {
|
|
173
|
+
console.log(`DeviceManager websocket closed`);
|
|
174
|
+
this._websocket = null;
|
|
175
|
+
};
|
|
176
|
+
this._websocket.onerror = (error) => {
|
|
177
|
+
console.warn(`DeviceManager websocket error ${error}`);
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
console.warn(`DeviceManager websocket error ${error}`);
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
////////////////////////////////////////////////////////////////////////////
|
|
187
|
+
// Callbacks
|
|
188
|
+
////////////////////////////////////////////////////////////////////////////
|
|
189
|
+
// Register state change callbacks
|
|
190
|
+
onNewDevice(callback) {
|
|
191
|
+
// Save the callback
|
|
192
|
+
this._callbackNewDevice = callback;
|
|
193
|
+
}
|
|
194
|
+
onNewDeviceAttribute(callback) {
|
|
195
|
+
// Save the callback
|
|
196
|
+
this._callbackNewDeviceAttribute = callback;
|
|
197
|
+
}
|
|
198
|
+
onNewAttributeData(callback) {
|
|
199
|
+
// Save the callback
|
|
200
|
+
this._callbackNewAttributeData = callback;
|
|
201
|
+
}
|
|
202
|
+
////////////////////////////////////////////////////////////////////////////
|
|
203
|
+
// Set the friendly name for the device
|
|
204
|
+
////////////////////////////////////////////////////////////////////////////
|
|
205
|
+
async setFriendlyName(friendlyName) {
|
|
206
|
+
try {
|
|
207
|
+
await fetch(this._serverAddressPrefix + this._urlPrefix + "/friendlyname/" + friendlyName);
|
|
208
|
+
}
|
|
209
|
+
catch (error) {
|
|
210
|
+
console.log(`DeviceManager setFriendlyName ${error}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
////////////////////////////////////////////////////////////////////////////
|
|
214
|
+
// Handle device message JSON
|
|
215
|
+
////////////////////////////////////////////////////////////////////////////
|
|
216
|
+
handleClientMsgJson(jsonMsg) {
|
|
217
|
+
const removeDevicesNoLongerPresent = true;
|
|
218
|
+
let data = JSON.parse(jsonMsg);
|
|
219
|
+
// console.log(`DeviceManager websocket message ${JSON.stringify(data)}`);
|
|
220
|
+
// Iterate over the buses
|
|
221
|
+
Object.entries(data).forEach(([busName, devices]) => {
|
|
222
|
+
// Check for bus status info
|
|
223
|
+
if (devices && typeof devices === "object" && "_s" in devices) {
|
|
224
|
+
// console.log(`DeviceManager bus status ${JSON.stringify(devices._s)}`);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
// Get a list of keys for the current devicesState
|
|
228
|
+
const deviceKeysToRemove = Object.keys(this._devicesState);
|
|
229
|
+
// Iterate over the devices
|
|
230
|
+
Object.entries(devices).forEach(async ([devAddr, attrGroups]) => {
|
|
231
|
+
// Check for non-device info (starts with _)
|
|
232
|
+
if (devAddr.startsWith("_")) {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
// Device key
|
|
236
|
+
const deviceKey = (0, RaftDeviceStates_1.getDeviceKey)(busName, devAddr);
|
|
237
|
+
// Remove from the list of keys for the current devicesState
|
|
238
|
+
const idx = deviceKeysToRemove.indexOf(deviceKey);
|
|
239
|
+
if (idx >= 0) {
|
|
240
|
+
deviceKeysToRemove.splice(idx, 1);
|
|
241
|
+
}
|
|
242
|
+
// Check if a device state already exists
|
|
243
|
+
if (!(deviceKey in this._devicesState)) {
|
|
244
|
+
let deviceTypeName = "";
|
|
245
|
+
if (attrGroups && typeof attrGroups === 'object' && "_t" in attrGroups && typeof attrGroups._t === "string") {
|
|
246
|
+
deviceTypeName = attrGroups._t || "";
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
console.warn(`DeviceManager missing device type attrGroups ${JSON.stringify(attrGroups)}`);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
// Create device record
|
|
253
|
+
this._devicesState[deviceKey] = {
|
|
254
|
+
deviceTypeInfo: await this.getDeviceTypeInfo(busName, devAddr, deviceTypeName),
|
|
255
|
+
deviceTimeline: {
|
|
256
|
+
timestampsUs: [],
|
|
257
|
+
lastReportTimestampUs: 0,
|
|
258
|
+
reportTimestampOffsetUs: 0
|
|
259
|
+
},
|
|
260
|
+
deviceAttributes: {},
|
|
261
|
+
deviceIsNew: true,
|
|
262
|
+
stateChanged: false,
|
|
263
|
+
isOnline: true
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
// Get device state
|
|
267
|
+
const deviceState = this._devicesState[deviceKey];
|
|
268
|
+
// Check for online/offline state information
|
|
269
|
+
if (attrGroups && typeof attrGroups === "object" && "_o" in attrGroups) {
|
|
270
|
+
deviceState.isOnline = ((attrGroups._o === true) || (attrGroups._o === "1") || (attrGroups._o === 1));
|
|
271
|
+
}
|
|
272
|
+
// Iterate attribute groups
|
|
273
|
+
Object.entries(attrGroups).forEach(([attrGroupName, msgHexStr]) => {
|
|
274
|
+
// Check valid
|
|
275
|
+
if (attrGroupName.startsWith("_") || (typeof msgHexStr != 'string')) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
// Check the device type info
|
|
279
|
+
if (!deviceState.deviceTypeInfo.resp) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
// Convert the hex string to an arraybuffer by converting each pair of hex chars to a byte
|
|
283
|
+
const msgBytes = this.hexToBytes(msgHexStr);
|
|
284
|
+
// Convert to a Buffer
|
|
285
|
+
const msgBuffer = Buffer.from(msgBytes);
|
|
286
|
+
// Work through the message which may contain multiple data instances
|
|
287
|
+
let msgBufIdx = 0;
|
|
288
|
+
// Iterate over attributes in the group
|
|
289
|
+
const pollRespMetadata = deviceState.deviceTypeInfo.resp;
|
|
290
|
+
// Loop
|
|
291
|
+
while (msgBufIdx < msgBytes.length) {
|
|
292
|
+
const curTimelineLen = deviceState.deviceTimeline.timestampsUs.length;
|
|
293
|
+
const newMsgBufIdx = this._attributeHandler.processMsgAttrGroup(msgBuffer, msgBufIdx, deviceState.deviceTimeline, pollRespMetadata, deviceState.deviceAttributes, this._maxDatapointsToStore);
|
|
294
|
+
if (newMsgBufIdx < 0)
|
|
295
|
+
break;
|
|
296
|
+
msgBufIdx = newMsgBufIdx;
|
|
297
|
+
if (deviceState.deviceTimeline.timestampsUs.length !== curTimelineLen) {
|
|
298
|
+
deviceState.stateChanged = true;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
// Remove devices no longer present
|
|
304
|
+
if (removeDevicesNoLongerPresent) {
|
|
305
|
+
deviceKeysToRemove.forEach((deviceKey) => {
|
|
306
|
+
delete this._devicesState[deviceKey];
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
// Update the last state update time
|
|
311
|
+
this._lastStateUpdate = Date.now();
|
|
312
|
+
// Process the callback
|
|
313
|
+
this.processStateCallback();
|
|
314
|
+
}
|
|
315
|
+
////////////////////////////////////////////////////////////////////////////
|
|
316
|
+
// Process state change callback
|
|
317
|
+
////////////////////////////////////////////////////////////////////////////
|
|
318
|
+
processStateCallback() {
|
|
319
|
+
// Iterate over the devices
|
|
320
|
+
Object.entries(this._devicesState).forEach(([deviceKey, deviceState]) => {
|
|
321
|
+
// Check if device record is new
|
|
322
|
+
if (deviceState.deviceIsNew) {
|
|
323
|
+
if (this._callbackNewDevice) {
|
|
324
|
+
this._callbackNewDevice(deviceKey, deviceState);
|
|
325
|
+
}
|
|
326
|
+
deviceState.deviceIsNew = false;
|
|
327
|
+
}
|
|
328
|
+
// Iterate over the attributes
|
|
329
|
+
Object.entries(deviceState.deviceAttributes).forEach(([_attrKey, attrState]) => {
|
|
330
|
+
if (attrState.newAttribute) {
|
|
331
|
+
if (this._callbackNewDeviceAttribute) {
|
|
332
|
+
this._callbackNewDeviceAttribute(deviceKey, attrState);
|
|
333
|
+
}
|
|
334
|
+
attrState.newAttribute = false;
|
|
335
|
+
}
|
|
336
|
+
if (attrState.newData) {
|
|
337
|
+
if (this._callbackNewAttributeData) {
|
|
338
|
+
this._callbackNewAttributeData(deviceKey, attrState);
|
|
339
|
+
}
|
|
340
|
+
attrState.newData = false;
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
////////////////////////////////////////////////////////////////////////////
|
|
346
|
+
// Get device type info
|
|
347
|
+
////////////////////////////////////////////////////////////////////////////
|
|
348
|
+
async getDeviceTypeInfo(busName, _devAddr, deviceType) {
|
|
349
|
+
const emptyRec = {
|
|
350
|
+
"name": "Unknown",
|
|
351
|
+
"desc": "Unknown",
|
|
352
|
+
"manu": "Unknown",
|
|
353
|
+
"type": "Unknown"
|
|
354
|
+
};
|
|
355
|
+
// Ensure that this._testDeviceTypeRecs and devTypes[deviceType] are properly initialized
|
|
356
|
+
if (process.env.TEST_DATA) {
|
|
357
|
+
if (this._testDeviceTypeRecs && this._testDeviceTypeRecs.devTypes[deviceType]) {
|
|
358
|
+
return this._testDeviceTypeRecs.devTypes[deviceType].devInfoJson;
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
// Handle the case where the necessary data isn't available
|
|
362
|
+
console.error("Device type info not available for:", deviceType);
|
|
363
|
+
return emptyRec;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
// Check if already in the cache
|
|
367
|
+
if (deviceType in this._cachedDeviceTypeRecs) {
|
|
368
|
+
return this._cachedDeviceTypeRecs[deviceType];
|
|
369
|
+
}
|
|
370
|
+
// Get the device type info from the server
|
|
371
|
+
try {
|
|
372
|
+
const getDevTypeInfoResponse = await fetch(this._serverAddressPrefix + this._urlPrefix + "/devman/typeinfo?bus=" + busName + "&type=" + deviceType);
|
|
373
|
+
if (!getDevTypeInfoResponse.ok) {
|
|
374
|
+
console.error(`DeviceManager getDeviceTypeInfo response not ok ${getDevTypeInfoResponse.status}`);
|
|
375
|
+
return emptyRec;
|
|
376
|
+
}
|
|
377
|
+
const devTypeInfo = await getDevTypeInfoResponse.json();
|
|
378
|
+
if ("devinfo" in devTypeInfo) {
|
|
379
|
+
this._cachedDeviceTypeRecs[deviceType] = devTypeInfo.devinfo;
|
|
380
|
+
return devTypeInfo.devinfo;
|
|
381
|
+
}
|
|
382
|
+
return emptyRec;
|
|
383
|
+
}
|
|
384
|
+
catch (error) {
|
|
385
|
+
console.error(`DeviceManager getDeviceTypeInfo error ${error}`);
|
|
386
|
+
return emptyRec;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
////////////////////////////////////////////////////////////////////////////
|
|
390
|
+
// Send action to device
|
|
391
|
+
////////////////////////////////////////////////////////////////////////////
|
|
392
|
+
sendAction(deviceKey, action, data) {
|
|
393
|
+
// console.log(`DeviceManager sendAction ${deviceKey} action name ${action.n} value ${value} prefix ${action.w}`);
|
|
394
|
+
// Form the write bytes
|
|
395
|
+
let writeBytes = action.t ? python_struct_1.default.pack(action.t, data) : Buffer.from([]);
|
|
396
|
+
// Convert to hex string
|
|
397
|
+
let writeHexStr = Buffer.from(writeBytes).toString('hex');
|
|
398
|
+
// Add prefix
|
|
399
|
+
writeHexStr = action.w + writeHexStr;
|
|
400
|
+
// Separate the bus and address in the deviceKey (_ char)
|
|
401
|
+
const devBus = deviceKey.split("_")[0];
|
|
402
|
+
const devAddr = deviceKey.split("_")[1];
|
|
403
|
+
// Send the action to the server
|
|
404
|
+
const url = this._serverAddressPrefix + this._urlPrefix + "/devman/cmdraw?bus=" + devBus + "&addr=" + devAddr + "&hexWr=" + writeHexStr;
|
|
405
|
+
console.log(`DeviceManager deviceKey ${deviceKey} action name ${action.n} value ${data} prefix ${action.w} sendAction ${url}`);
|
|
406
|
+
fetch(url)
|
|
407
|
+
.then(response => {
|
|
408
|
+
if (!response.ok) {
|
|
409
|
+
console.error(`DeviceManager sendAction response not ok ${response.status}`);
|
|
410
|
+
}
|
|
411
|
+
})
|
|
412
|
+
.catch(error => {
|
|
413
|
+
console.error(`DeviceManager sendAction error ${error}`);
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
////////////////////////////////////////////////////////////////////////////
|
|
417
|
+
// Send a compound action to the device
|
|
418
|
+
////////////////////////////////////////////////////////////////////////////
|
|
419
|
+
sendCompoundAction(deviceKey, action, data) {
|
|
420
|
+
// console.log(`DeviceManager sendAction ${deviceKey} action name ${action.n} value ${value} prefix ${action.w}`);
|
|
421
|
+
// Check if all data to be sent at once
|
|
422
|
+
if (action.concat) {
|
|
423
|
+
// Form a single list by flattening data
|
|
424
|
+
let dataToWrite = [];
|
|
425
|
+
for (let dataIdx = 0; dataIdx < data.length; dataIdx++) {
|
|
426
|
+
dataToWrite = dataToWrite.concat(data[dataIdx]);
|
|
427
|
+
}
|
|
428
|
+
// Use sendAction to send this
|
|
429
|
+
this.sendAction(deviceKey, action, dataToWrite);
|
|
430
|
+
}
|
|
431
|
+
else {
|
|
432
|
+
// Iterate over the data
|
|
433
|
+
for (let dataIdx = 0; dataIdx < data.length; dataIdx++) {
|
|
434
|
+
// Create the data to write by prepending the index to the data for this index
|
|
435
|
+
let dataToWrite = [dataIdx].concat(data[dataIdx]);
|
|
436
|
+
// Use sendAction to send this
|
|
437
|
+
this.sendAction(deviceKey, action, dataToWrite);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
hexToBytes(hex) {
|
|
442
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
443
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
444
|
+
bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
|
|
445
|
+
}
|
|
446
|
+
return bytes;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
exports.DeviceManager = DeviceManager;
|
|
450
|
+
//# sourceMappingURL=RaftDeviceManager.js.map
|