@robotical/raftjs 1.3.3
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 +13 -0
- package/TODO.md +1 -0
- package/dist/react-native/RaftAttributeHandler.d.ts +12 -0
- package/dist/react-native/RaftAttributeHandler.js +241 -0
- package/dist/react-native/RaftAttributeHandler.js.map +1 -0
- package/dist/react-native/RaftChannel.d.ts +18 -0
- package/dist/react-native/RaftChannel.js +12 -0
- package/dist/react-native/RaftChannel.js.map +1 -0
- package/dist/react-native/RaftChannelBLE.native.d.ts +93 -0
- package/dist/react-native/RaftChannelBLE.native.js +455 -0
- package/dist/react-native/RaftChannelBLE.native.js.map +1 -0
- package/dist/react-native/RaftChannelBLE.web.d.ts +39 -0
- package/dist/react-native/RaftChannelBLE.web.js +294 -0
- package/dist/react-native/RaftChannelBLE.web.js.map +1 -0
- package/dist/react-native/RaftChannelBLEFactory.d.ts +10 -0
- package/dist/react-native/RaftChannelBLEFactory.js +17 -0
- package/dist/react-native/RaftChannelBLEFactory.js.map +1 -0
- package/dist/react-native/RaftChannelBLEScanner.native.d.ts +18 -0
- package/dist/react-native/RaftChannelBLEScanner.native.js +146 -0
- package/dist/react-native/RaftChannelBLEScanner.native.js.map +1 -0
- package/dist/react-native/RaftChannelWebSerial.d.ts +37 -0
- package/dist/react-native/RaftChannelWebSerial.js +320 -0
- package/dist/react-native/RaftChannelWebSerial.js.map +1 -0
- package/dist/react-native/RaftChannelWebSocket.d.ts +28 -0
- package/dist/react-native/RaftChannelWebSocket.js +197 -0
- package/dist/react-native/RaftChannelWebSocket.js.map +1 -0
- package/dist/react-native/RaftCommsStats.d.ts +39 -0
- package/dist/react-native/RaftCommsStats.js +128 -0
- package/dist/react-native/RaftCommsStats.js.map +1 -0
- package/dist/react-native/RaftConnEvents.d.ts +39 -0
- package/dist/react-native/RaftConnEvents.js +54 -0
- package/dist/react-native/RaftConnEvents.js.map +1 -0
- package/dist/react-native/RaftConnector.d.ts +245 -0
- package/dist/react-native/RaftConnector.js +614 -0
- package/dist/react-native/RaftConnector.js.map +1 -0
- package/dist/react-native/RaftCustomAttrHandler.d.ts +4 -0
- package/dist/react-native/RaftCustomAttrHandler.js +50 -0
- package/dist/react-native/RaftCustomAttrHandler.js.map +1 -0
- package/dist/react-native/RaftDeviceInfo.d.ts +59 -0
- package/dist/react-native/RaftDeviceInfo.js +36 -0
- package/dist/react-native/RaftDeviceInfo.js.map +1 -0
- package/dist/react-native/RaftDeviceManager.d.ts +35 -0
- package/dist/react-native/RaftDeviceManager.js +353 -0
- package/dist/react-native/RaftDeviceManager.js.map +1 -0
- package/dist/react-native/RaftDeviceMgrIF.d.ts +12 -0
- package/dist/react-native/RaftDeviceMgrIF.js +11 -0
- package/dist/react-native/RaftDeviceMgrIF.js.map +1 -0
- package/dist/react-native/RaftDeviceMsg.d.ts +9 -0
- package/dist/react-native/RaftDeviceMsg.js +11 -0
- package/dist/react-native/RaftDeviceMsg.js.map +1 -0
- package/dist/react-native/RaftDeviceStates.d.ts +33 -0
- package/dist/react-native/RaftDeviceStates.js +60 -0
- package/dist/react-native/RaftDeviceStates.js.map +1 -0
- package/dist/react-native/RaftFileHandler.d.ts +52 -0
- package/dist/react-native/RaftFileHandler.js +502 -0
- package/dist/react-native/RaftFileHandler.js.map +1 -0
- package/dist/react-native/RaftLog.d.ts +22 -0
- package/dist/react-native/RaftLog.js +63 -0
- package/dist/react-native/RaftLog.js.map +1 -0
- package/dist/react-native/RaftMiniHDLC.d.ts +18 -0
- package/dist/react-native/RaftMiniHDLC.js +383 -0
- package/dist/react-native/RaftMiniHDLC.js.map +1 -0
- package/dist/react-native/RaftMsgHandler.d.ts +57 -0
- package/dist/react-native/RaftMsgHandler.js +480 -0
- package/dist/react-native/RaftMsgHandler.js.map +1 -0
- package/dist/react-native/RaftMsgTrackInfo.d.ts +17 -0
- package/dist/react-native/RaftMsgTrackInfo.js +42 -0
- package/dist/react-native/RaftMsgTrackInfo.js.map +1 -0
- package/dist/react-native/RaftProtocolDefs.d.ts +30 -0
- package/dist/react-native/RaftProtocolDefs.js +48 -0
- package/dist/react-native/RaftProtocolDefs.js.map +1 -0
- package/dist/react-native/RaftStreamHandler.d.ts +38 -0
- package/dist/react-native/RaftStreamHandler.js +257 -0
- package/dist/react-native/RaftStreamHandler.js.map +1 -0
- package/dist/react-native/RaftSystemType.d.ts +25 -0
- package/dist/react-native/RaftSystemType.js +3 -0
- package/dist/react-native/RaftSystemType.js.map +1 -0
- package/dist/react-native/RaftSystemUtils.d.ts +136 -0
- package/dist/react-native/RaftSystemUtils.js +410 -0
- package/dist/react-native/RaftSystemUtils.js.map +1 -0
- package/dist/react-native/RaftTypes.d.ts +195 -0
- package/dist/react-native/RaftTypes.js +190 -0
- package/dist/react-native/RaftTypes.js.map +1 -0
- package/dist/react-native/RaftUpdateEvents.d.ts +33 -0
- package/dist/react-native/RaftUpdateEvents.js +46 -0
- package/dist/react-native/RaftUpdateEvents.js.map +1 -0
- package/dist/react-native/RaftUpdateManager.d.ts +61 -0
- package/dist/react-native/RaftUpdateManager.js +618 -0
- package/dist/react-native/RaftUpdateManager.js.map +1 -0
- package/dist/react-native/RaftUtils.d.ts +125 -0
- package/dist/react-native/RaftUtils.js +454 -0
- package/dist/react-native/RaftUtils.js.map +1 -0
- package/dist/react-native/RaftWifiTypes.d.ts +23 -0
- package/dist/react-native/RaftWifiTypes.js +43 -0
- package/dist/react-native/RaftWifiTypes.js.map +1 -0
- package/dist/react-native/main.d.ts +22 -0
- package/dist/react-native/main.js +48 -0
- package/dist/react-native/main.js.map +1 -0
- package/dist/web/RaftAttributeHandler.d.ts +12 -0
- package/dist/web/RaftAttributeHandler.js +241 -0
- package/dist/web/RaftAttributeHandler.js.map +1 -0
- package/dist/web/RaftChannel.d.ts +18 -0
- package/dist/web/RaftChannel.js +12 -0
- package/dist/web/RaftChannel.js.map +1 -0
- package/dist/web/RaftChannelBLE.web.d.ts +39 -0
- package/dist/web/RaftChannelBLE.web.js +294 -0
- package/dist/web/RaftChannelBLE.web.js.map +1 -0
- package/dist/web/RaftChannelBLEFactory.d.ts +10 -0
- package/dist/web/RaftChannelBLEFactory.js +17 -0
- package/dist/web/RaftChannelBLEFactory.js.map +1 -0
- package/dist/web/RaftChannelWebSerial.d.ts +37 -0
- package/dist/web/RaftChannelWebSerial.js +320 -0
- package/dist/web/RaftChannelWebSerial.js.map +1 -0
- package/dist/web/RaftChannelWebSocket.d.ts +28 -0
- package/dist/web/RaftChannelWebSocket.js +197 -0
- package/dist/web/RaftChannelWebSocket.js.map +1 -0
- package/dist/web/RaftCommsStats.d.ts +39 -0
- package/dist/web/RaftCommsStats.js +128 -0
- package/dist/web/RaftCommsStats.js.map +1 -0
- package/dist/web/RaftConnEvents.d.ts +39 -0
- package/dist/web/RaftConnEvents.js +54 -0
- package/dist/web/RaftConnEvents.js.map +1 -0
- package/dist/web/RaftConnector.d.ts +245 -0
- package/dist/web/RaftConnector.js +614 -0
- package/dist/web/RaftConnector.js.map +1 -0
- package/dist/web/RaftCustomAttrHandler.d.ts +4 -0
- package/dist/web/RaftCustomAttrHandler.js +50 -0
- package/dist/web/RaftCustomAttrHandler.js.map +1 -0
- package/dist/web/RaftDeviceInfo.d.ts +59 -0
- package/dist/web/RaftDeviceInfo.js +36 -0
- package/dist/web/RaftDeviceInfo.js.map +1 -0
- package/dist/web/RaftDeviceManager.d.ts +35 -0
- package/dist/web/RaftDeviceManager.js +353 -0
- package/dist/web/RaftDeviceManager.js.map +1 -0
- package/dist/web/RaftDeviceMgrIF.d.ts +12 -0
- package/dist/web/RaftDeviceMgrIF.js +11 -0
- package/dist/web/RaftDeviceMgrIF.js.map +1 -0
- package/dist/web/RaftDeviceMsg.d.ts +9 -0
- package/dist/web/RaftDeviceMsg.js +11 -0
- package/dist/web/RaftDeviceMsg.js.map +1 -0
- package/dist/web/RaftDeviceStates.d.ts +33 -0
- package/dist/web/RaftDeviceStates.js +60 -0
- package/dist/web/RaftDeviceStates.js.map +1 -0
- package/dist/web/RaftFileHandler.d.ts +52 -0
- package/dist/web/RaftFileHandler.js +502 -0
- package/dist/web/RaftFileHandler.js.map +1 -0
- package/dist/web/RaftLog.d.ts +22 -0
- package/dist/web/RaftLog.js +63 -0
- package/dist/web/RaftLog.js.map +1 -0
- package/dist/web/RaftMiniHDLC.d.ts +18 -0
- package/dist/web/RaftMiniHDLC.js +383 -0
- package/dist/web/RaftMiniHDLC.js.map +1 -0
- package/dist/web/RaftMsgHandler.d.ts +57 -0
- package/dist/web/RaftMsgHandler.js +480 -0
- package/dist/web/RaftMsgHandler.js.map +1 -0
- package/dist/web/RaftMsgTrackInfo.d.ts +17 -0
- package/dist/web/RaftMsgTrackInfo.js +42 -0
- package/dist/web/RaftMsgTrackInfo.js.map +1 -0
- package/dist/web/RaftProtocolDefs.d.ts +30 -0
- package/dist/web/RaftProtocolDefs.js +48 -0
- package/dist/web/RaftProtocolDefs.js.map +1 -0
- package/dist/web/RaftStreamHandler.d.ts +38 -0
- package/dist/web/RaftStreamHandler.js +257 -0
- package/dist/web/RaftStreamHandler.js.map +1 -0
- package/dist/web/RaftSystemType.d.ts +25 -0
- package/dist/web/RaftSystemType.js +3 -0
- package/dist/web/RaftSystemType.js.map +1 -0
- package/dist/web/RaftSystemUtils.d.ts +136 -0
- package/dist/web/RaftSystemUtils.js +410 -0
- package/dist/web/RaftSystemUtils.js.map +1 -0
- package/dist/web/RaftTypes.d.ts +195 -0
- package/dist/web/RaftTypes.js +190 -0
- package/dist/web/RaftTypes.js.map +1 -0
- package/dist/web/RaftUpdateEvents.d.ts +33 -0
- package/dist/web/RaftUpdateEvents.js +46 -0
- package/dist/web/RaftUpdateEvents.js.map +1 -0
- package/dist/web/RaftUpdateManager.d.ts +61 -0
- package/dist/web/RaftUpdateManager.js +618 -0
- package/dist/web/RaftUpdateManager.js.map +1 -0
- package/dist/web/RaftUtils.d.ts +125 -0
- package/dist/web/RaftUtils.js +454 -0
- package/dist/web/RaftUtils.js.map +1 -0
- package/dist/web/RaftWifiTypes.d.ts +23 -0
- package/dist/web/RaftWifiTypes.js +43 -0
- package/dist/web/RaftWifiTypes.js.map +1 -0
- package/dist/web/main.d.ts +22 -0
- package/dist/web/main.js +48 -0
- package/dist/web/main.js.map +1 -0
- package/eslint.config.mjs +33 -0
- package/examples/dashboard/package.json +43 -0
- package/examples/dashboard/src/CommandPanel.tsx +147 -0
- package/examples/dashboard/src/ConnManager.ts +85 -0
- package/examples/dashboard/src/DeviceActionsForm.tsx +133 -0
- package/examples/dashboard/src/DeviceAttrsForm.tsx +49 -0
- package/examples/dashboard/src/DeviceLineChart.tsx +139 -0
- package/examples/dashboard/src/DevicePanel.tsx +135 -0
- package/examples/dashboard/src/DevicesPanel.tsx +57 -0
- package/examples/dashboard/src/DispLedGrid.tsx +110 -0
- package/examples/dashboard/src/DispOneLed.tsx +20 -0
- package/examples/dashboard/src/Main.tsx +106 -0
- package/examples/dashboard/src/StatusPanel.tsx +71 -0
- package/examples/dashboard/src/SystemTypeCog/CogStateInfo.ts +157 -0
- package/examples/dashboard/src/SystemTypeCog/SystemTypeCog.ts +84 -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 +78 -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 +116 -0
- package/examples/dashboard/src/index.html +15 -0
- package/examples/dashboard/src/index.tsx +15 -0
- package/examples/dashboard/src/styles.css +386 -0
- package/examples/dashboard/tsconfig.json +18 -0
- package/jest.config.js +11 -0
- package/package.json +59 -0
- package/src/RaftAttributeHandler.ts +289 -0
- package/src/RaftChannel.ts +30 -0
- package/src/RaftChannelBLE.native.ts +583 -0
- package/src/RaftChannelBLE.web.ts +362 -0
- package/src/RaftChannelBLEFactory.ts +13 -0
- package/src/RaftChannelBLEScanner.native.ts +190 -0
- package/src/RaftChannelWebSerial.ts +409 -0
- package/src/RaftChannelWebSocket.ts +245 -0
- package/src/RaftCommsStats.ts +142 -0
- package/src/RaftConnEvents.ts +58 -0
- package/src/RaftConnector.ts +737 -0
- package/src/RaftCustomAttrHandler.ts +54 -0
- package/src/RaftDeviceInfo.ts +98 -0
- package/src/RaftDeviceManager.ts +436 -0
- package/src/RaftDeviceMgrIF.ts +28 -0
- package/src/RaftDeviceMsg.ts +20 -0
- package/src/RaftDeviceStates.ts +88 -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 +29 -0
- package/src/RaftSystemUtils.ts +487 -0
- package/src/RaftTypes.ts +281 -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/main.ts +36 -0
- package/testdata/TestDeviceTypeRecs.json +492 -0
- package/tsconfig.json +30 -0
- package/tsconfig.react-native.json +29 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
//
|
|
3
|
+
// RaftCustomAttrHandler
|
|
4
|
+
// Custom attribute handler for Raft devices
|
|
5
|
+
//
|
|
6
|
+
// Rob Dobson (C) 2024
|
|
7
|
+
//
|
|
8
|
+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
9
|
+
|
|
10
|
+
import { DeviceTypePollRespMetadata } from "./RaftDeviceInfo";
|
|
11
|
+
|
|
12
|
+
export default class CustomAttrHandler {
|
|
13
|
+
|
|
14
|
+
public handleAttr(pollRespMetadata: DeviceTypePollRespMetadata, msgBuffer: Buffer, msgBufIdx: number): number[][] {
|
|
15
|
+
|
|
16
|
+
// Number of bytes in the each message
|
|
17
|
+
const numMsgBytes = pollRespMetadata.b;
|
|
18
|
+
|
|
19
|
+
// Create a vector for each attribute in the metadata
|
|
20
|
+
let attrValueVecs: [][] = [];
|
|
21
|
+
|
|
22
|
+
// Reference to each vector by attribute name
|
|
23
|
+
let attrValues: { [key: string]: number[] } = {};
|
|
24
|
+
|
|
25
|
+
// Add attributes to the vector
|
|
26
|
+
for (let attrIdx = 0; attrIdx < pollRespMetadata.a.length; attrIdx++) {
|
|
27
|
+
attrValueVecs.push([]);
|
|
28
|
+
attrValues[pollRespMetadata.a[attrIdx].n] = attrValueVecs[attrIdx];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Custom code for each device type
|
|
32
|
+
if (pollRespMetadata.c!.n === "max30101_fifo") {
|
|
33
|
+
// Hex dump msgBuffer
|
|
34
|
+
// console.log(`CustomAttrHandler handleAttr ${pollRespMetadata.c!.n} msgBuffer: ${msgBuffer.toString('hex')}`);
|
|
35
|
+
let buf = msgBuffer.slice(msgBufIdx);
|
|
36
|
+
if (buf.length < numMsgBytes) {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Generated code ...
|
|
41
|
+
let N=(buf[0]+32-buf[2])%32;
|
|
42
|
+
let k=3;
|
|
43
|
+
let i=0;
|
|
44
|
+
while (i<N) {
|
|
45
|
+
attrValues['Red'].push(0); attrValues['Red'][attrValues['Red'].length-1] =(buf[k]<<16)|(buf[k+1]<<8)|buf[k+2];
|
|
46
|
+
attrValues['IR'].push(0); attrValues['IR'][attrValues['IR'].length-1] =(buf[k+3]<<16)|(buf[k+4]<<8)|buf[k+5];
|
|
47
|
+
k+=6;
|
|
48
|
+
i++;
|
|
49
|
+
;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return attrValueVecs;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
//
|
|
3
|
+
// RaftDeviceInfo
|
|
4
|
+
// Device information for Raft devices
|
|
5
|
+
//
|
|
6
|
+
// Rob Dobson (C) 2024
|
|
7
|
+
//
|
|
8
|
+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
9
|
+
|
|
10
|
+
const attrTypeBits: { [key: string]: number } = {
|
|
11
|
+
"c": 8, "b": 8, "B": 8, "?": 8,
|
|
12
|
+
"h": 16, "H": 16, ">h": 16, "<h": 16, ">H": 16, "<H": 16,
|
|
13
|
+
"i": 32, "I": 32, ">i": 32, "<i": 32, ">I": 32, "<I": 32, "l": 32, "L": 32, ">l": 32, "<l": 32, ">L": 32, "<L": 32,
|
|
14
|
+
"q": 64, "Q": 64, ">q": 64, "<q": 64, ">Q": 64, "<Q": 64,
|
|
15
|
+
"f": 32, ">f": 32, "<f": 32,
|
|
16
|
+
"d": 64, ">d": 64, "<d": 64,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export function getAttrTypeBits(attrType: string): number {
|
|
20
|
+
if (attrType in attrTypeBits) {
|
|
21
|
+
return attrTypeBits[attrType];
|
|
22
|
+
}
|
|
23
|
+
return 8;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function isAttrTypeSigned(attrType: string): boolean {
|
|
27
|
+
const attrStr = attrType.charAt(0) === ">" || attrType.charAt(0) === "<" ? attrType.slice(1).charAt(0) : attrType.charAt(0);
|
|
28
|
+
return attrStr === "b" || attrStr === "h" || attrStr === "i" || attrStr === "l" || attrStr === "q";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function decodeAttrUnitsEncoding(unitsEncoding: string): string {
|
|
32
|
+
// Replace instances of HTML encoded chars like ° with the actual char
|
|
33
|
+
return unitsEncoding.replace(/°/g, "°");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface DeviceTypeAttribute {
|
|
37
|
+
n: string; // Name
|
|
38
|
+
t: string; // Type in python struct module format (e.g. 'H' uint16, 'h' int16, 'f' float etc.)
|
|
39
|
+
at?: number; // Start pos in buffer (after timestamp) if present (otherwise use relative position)
|
|
40
|
+
u?: string; // Units (e.g. mm)
|
|
41
|
+
r?: number[]; // Range (either min, max or min, max, step or discrete values)
|
|
42
|
+
x?: number; // XOR bit mask to invert bits in the attribute value
|
|
43
|
+
m?: number | string; // AND bit mask to extract the attribute value from the message
|
|
44
|
+
s?: number; // Shift value to shift the attribute value to the right (or left if negative)
|
|
45
|
+
sb?: number; // Sign-bit position (0-based)
|
|
46
|
+
ss?: number; // Sign-bit subtraction value
|
|
47
|
+
d?: number; // Divisor to convert the raw attribute value (after operations above) to the actual value
|
|
48
|
+
a?: number; // Value to add after division
|
|
49
|
+
f?: string; // Format string similar to C printf format string (e.g. %d, %x, %f, %04d, %08x, %08.2f etc.), %b = boolean (0 iff 0, else 1)
|
|
50
|
+
o?: string; // Type of output value (e.g. 'bool', 'uint8', 'float')
|
|
51
|
+
v?: boolean | number; // Visibility of the attribute in all locations (mainly used to hide attributes that are not useful to the user)
|
|
52
|
+
vs?: boolean | number; // Display attribute value in time-series graphs
|
|
53
|
+
vf?: boolean | number; // Display attribute value in the device info panel
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface CustomFunctionDefinition {
|
|
57
|
+
n: string; // Function name
|
|
58
|
+
c: string; // Function pseudo-code
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface DeviceTypePollRespMetadata {
|
|
62
|
+
b: number; // Size of polled response data block in bytes (excluding timestamp)
|
|
63
|
+
a: DeviceTypeAttribute[]; // Attributes in the polled response
|
|
64
|
+
c?: CustomFunctionDefinition; // Custom function definition
|
|
65
|
+
us?: number; // Time between consecutive samples in microseconds
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface DeviceTypeAction {
|
|
69
|
+
n: string; // Action name
|
|
70
|
+
t?: string; // Action type using python struct module format (e.g. 'H' for unsigned short, 'h' for signed short, 'f' for float etc.)
|
|
71
|
+
w: string; // Prefix to write to cmd API
|
|
72
|
+
r?: number[]; // Range of valid values for the action
|
|
73
|
+
f?: string; // Custom formatting options (e.g. LEDPIX for LED pixel grid)
|
|
74
|
+
NX?: number; // Number of X in the LED pixel grid
|
|
75
|
+
NY?: number; // Number of Y in the LED pixel grid
|
|
76
|
+
concat?: boolean; // Concatenate the all values into a single command
|
|
77
|
+
d?: number; // Default value
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface DeviceTypeInfo {
|
|
81
|
+
name: string;
|
|
82
|
+
desc: string;
|
|
83
|
+
manu: string;
|
|
84
|
+
type: string;
|
|
85
|
+
resp?: DeviceTypePollRespMetadata;
|
|
86
|
+
actions?: DeviceTypeAction[];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface DeviceTypeInfoRecs {
|
|
90
|
+
[devType: string]: DeviceTypeInfo;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export type RaftDevTypeInfoResponse = {
|
|
94
|
+
req: string;
|
|
95
|
+
rslt: string;
|
|
96
|
+
devinfo: DeviceTypeInfo;
|
|
97
|
+
};
|
|
98
|
+
|
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
//
|
|
3
|
+
// RaftDeviceManager
|
|
4
|
+
// Device manager for Raft devices
|
|
5
|
+
//
|
|
6
|
+
// Rob Dobson (C) 2024
|
|
7
|
+
//
|
|
8
|
+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
9
|
+
|
|
10
|
+
import { DeviceAttributeState, DevicesState, DeviceState, getDeviceKey } from "./RaftDeviceStates";
|
|
11
|
+
import { DeviceMsgJson } from "./RaftDeviceMsg";
|
|
12
|
+
import { RaftOKFail } from './RaftTypes';
|
|
13
|
+
import { DeviceTypeInfo, DeviceTypeAction, DeviceTypeInfoRecs, RaftDevTypeInfoResponse } from "./RaftDeviceInfo";
|
|
14
|
+
import struct, { DataType } from 'python-struct';
|
|
15
|
+
import AttributeHandler from "./RaftAttributeHandler";
|
|
16
|
+
import RaftSystemUtils from "./RaftSystemUtils";
|
|
17
|
+
import RaftDeviceMgrIF from "./RaftDeviceMgrIF";
|
|
18
|
+
import { Buffer } from 'buffer';
|
|
19
|
+
|
|
20
|
+
export class DeviceManager implements RaftDeviceMgrIF{
|
|
21
|
+
|
|
22
|
+
// Singleton
|
|
23
|
+
// private static _instance: DeviceManager;
|
|
24
|
+
|
|
25
|
+
// Max data points to store
|
|
26
|
+
private _maxDatapointsToStore = 1000;
|
|
27
|
+
|
|
28
|
+
// Min time between attempts to retrieve device type info
|
|
29
|
+
private _minTimeBetweenDeviceTypeInfoRetrievalMs = 60000;
|
|
30
|
+
|
|
31
|
+
// Attribute handler
|
|
32
|
+
private _attributeHandler = new AttributeHandler();
|
|
33
|
+
|
|
34
|
+
// Devices state
|
|
35
|
+
private _devicesState = new DevicesState();
|
|
36
|
+
|
|
37
|
+
// Last time each device was updated - used to detect devices that are no longer present
|
|
38
|
+
private _deviceLastUpdateTime: { [deviceKey: string]: number } = {};
|
|
39
|
+
|
|
40
|
+
// Flag indicating that removed devices should be removed from the state
|
|
41
|
+
private _removeDevicesFlag = true;
|
|
42
|
+
private _removeDevicesTimeMs = 60000;
|
|
43
|
+
|
|
44
|
+
// System utils
|
|
45
|
+
private _systemUtils: RaftSystemUtils | null = null;
|
|
46
|
+
|
|
47
|
+
// Device callbacks
|
|
48
|
+
private _callbackNewDevice: ((deviceKey: string, state: DeviceState) => void) | null = null;
|
|
49
|
+
private _callbackNewDeviceAttribute: ((deviceKey: string, attrState: DeviceAttributeState) => void) | null = null;
|
|
50
|
+
private _callbackNewAttributeData: ((deviceKey: string, attrState: DeviceAttributeState) => void) | null = null;
|
|
51
|
+
|
|
52
|
+
public getDevicesState(): DevicesState {
|
|
53
|
+
return this._devicesState;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public getDeviceState(deviceKey: string): DeviceState {
|
|
57
|
+
return this._devicesState[deviceKey];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Cached device type data
|
|
61
|
+
private _cachedDeviceTypeRecs: DeviceTypeInfoRecs = {};
|
|
62
|
+
|
|
63
|
+
// Cached device type previous attempt times
|
|
64
|
+
private _cachedDeviceTypePreviousAttemptTimes: { [deviceType: string]: number } = {};
|
|
65
|
+
|
|
66
|
+
// Constructor
|
|
67
|
+
constructor() {
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
////////////////////////////////////////////////////////////////////////////
|
|
71
|
+
// Send REST commands
|
|
72
|
+
////////////////////////////////////////////////////////////////////////////
|
|
73
|
+
|
|
74
|
+
async sendCommand(cmd: string): Promise<boolean> {
|
|
75
|
+
try {
|
|
76
|
+
// Get the msg handler
|
|
77
|
+
const msgHandler = this._systemUtils?.getMsgHandler();
|
|
78
|
+
if (msgHandler) {
|
|
79
|
+
const msgRslt = await msgHandler.sendRICRESTURL<RaftOKFail>(cmd);
|
|
80
|
+
return msgRslt.isOk();
|
|
81
|
+
}
|
|
82
|
+
return false;
|
|
83
|
+
} catch (error) {
|
|
84
|
+
console.warn(`DeviceManager sendCommand error ${error}`);
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
////////////////////////////////////////////////////////////////////////////
|
|
90
|
+
// Setup
|
|
91
|
+
////////////////////////////////////////////////////////////////////////////
|
|
92
|
+
|
|
93
|
+
public async setup(systemUtils: RaftSystemUtils): Promise<boolean> {
|
|
94
|
+
|
|
95
|
+
// Save the system utils
|
|
96
|
+
this._systemUtils = systemUtils;
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
////////////////////////////////////////////////////////////////////////////
|
|
101
|
+
// Callbacks
|
|
102
|
+
////////////////////////////////////////////////////////////////////////////
|
|
103
|
+
|
|
104
|
+
// Register state change callbacks
|
|
105
|
+
public onNewDevice(callback: (deviceKey: string, state: DeviceState) => void): void {
|
|
106
|
+
// Save the callback
|
|
107
|
+
this._callbackNewDevice = callback;
|
|
108
|
+
}
|
|
109
|
+
public onNewDeviceAttribute(callback: (deviceKey: string, attrState: DeviceAttributeState) => void): void {
|
|
110
|
+
// Save the callback
|
|
111
|
+
this._callbackNewDeviceAttribute = callback;
|
|
112
|
+
}
|
|
113
|
+
public onNewAttributeData(callback: (deviceKey: string, attrState: DeviceAttributeState) => void): void {
|
|
114
|
+
// Save the callback
|
|
115
|
+
this._callbackNewAttributeData = callback;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
////////////////////////////////////////////////////////////////////////////
|
|
119
|
+
// Set the friendly name for the device
|
|
120
|
+
////////////////////////////////////////////////////////////////////////////
|
|
121
|
+
|
|
122
|
+
public async setFriendlyName(friendlyName: string): Promise<void> {
|
|
123
|
+
// Set using utils
|
|
124
|
+
await this._systemUtils?.setRaftName(friendlyName);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
////////////////////////////////////////////////////////////////////////////
|
|
128
|
+
// Handle device message JSON
|
|
129
|
+
////////////////////////////////////////////////////////////////////////////
|
|
130
|
+
|
|
131
|
+
public handleClientMsgJson(jsonMsg: string) {
|
|
132
|
+
|
|
133
|
+
let data = JSON.parse(jsonMsg) as DeviceMsgJson;
|
|
134
|
+
// console.log(`DeviceManager websocket message ${JSON.stringify(data)}`);
|
|
135
|
+
|
|
136
|
+
// Iterate over the buses
|
|
137
|
+
Object.entries(data).forEach(([busName, devices]) => {
|
|
138
|
+
|
|
139
|
+
// Check for bus status info
|
|
140
|
+
if (devices && typeof devices === "object" && "_s" in devices) {
|
|
141
|
+
// console.log(`DeviceManager bus status ${JSON.stringify(devices._s)}`);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Iterate over the devices
|
|
146
|
+
Object.entries(devices).forEach(async ([devAddr, attrGroups]) => {
|
|
147
|
+
|
|
148
|
+
// Check for non-device info (starts with _)
|
|
149
|
+
if (devAddr.startsWith("_")) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Device key
|
|
154
|
+
const deviceKey = getDeviceKey(busName, devAddr);
|
|
155
|
+
|
|
156
|
+
// Update the last update time
|
|
157
|
+
this._deviceLastUpdateTime[deviceKey] = Date.now();
|
|
158
|
+
|
|
159
|
+
// Check if a device state already exists
|
|
160
|
+
if (!(deviceKey in this._devicesState) || (this._devicesState[deviceKey].deviceTypeInfo === undefined)) {
|
|
161
|
+
|
|
162
|
+
let deviceTypeName = "";
|
|
163
|
+
if (attrGroups && typeof attrGroups === 'object' && "_t" in attrGroups && typeof attrGroups._t === "string") {
|
|
164
|
+
deviceTypeName = attrGroups._t || "";
|
|
165
|
+
} else {
|
|
166
|
+
console.warn(`DeviceManager missing device type attrGroups ${JSON.stringify(attrGroups)}`);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Get the device type info
|
|
171
|
+
const deviceTypeInfo = await this.getDeviceTypeInfo(busName, devAddr, deviceTypeName);
|
|
172
|
+
|
|
173
|
+
// Check if device record exists
|
|
174
|
+
if (deviceKey in this._devicesState) {
|
|
175
|
+
if (deviceTypeInfo !== undefined) {
|
|
176
|
+
this._devicesState[deviceKey].deviceTypeInfo = deviceTypeInfo;
|
|
177
|
+
}
|
|
178
|
+
} else {
|
|
179
|
+
// Create device record - device type info may be undefined
|
|
180
|
+
this._devicesState[deviceKey] = {
|
|
181
|
+
deviceTypeInfo: deviceTypeInfo,
|
|
182
|
+
deviceTimeline: {
|
|
183
|
+
timestampsUs: [],
|
|
184
|
+
lastReportTimestampUs: 0,
|
|
185
|
+
reportTimestampOffsetUs: 0
|
|
186
|
+
},
|
|
187
|
+
deviceAttributes: {},
|
|
188
|
+
deviceIsNew: true,
|
|
189
|
+
stateChanged: false,
|
|
190
|
+
isOnline: true
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Get device state
|
|
196
|
+
const deviceState = this._devicesState[deviceKey];
|
|
197
|
+
|
|
198
|
+
// Check for online/offline state information
|
|
199
|
+
if (attrGroups && typeof attrGroups === "object" && "_o" in attrGroups) {
|
|
200
|
+
deviceState.isOnline = ((attrGroups._o === true) || (attrGroups._o === "1") || (attrGroups._o === 1));
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Check if device type info is available
|
|
204
|
+
if (!deviceState.deviceTypeInfo) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Iterate attribute groups
|
|
209
|
+
Object.entries(attrGroups).forEach(([attrGroupName, msgHexStr]) => {
|
|
210
|
+
|
|
211
|
+
// Check valid
|
|
212
|
+
if (attrGroupName.startsWith("_") || (typeof msgHexStr != 'string')) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Check the device type info
|
|
217
|
+
if (!deviceState.deviceTypeInfo!.resp) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Convert the hex string to an arraybuffer by converting each pair of hex chars to a byte
|
|
222
|
+
const msgBytes = this.hexToBytes(msgHexStr);
|
|
223
|
+
|
|
224
|
+
// Convert to a Buffer
|
|
225
|
+
const msgBuffer = Buffer.from(msgBytes);
|
|
226
|
+
|
|
227
|
+
// Work through the message which may contain multiple data instances
|
|
228
|
+
let msgBufIdx = 0;
|
|
229
|
+
|
|
230
|
+
// Iterate over attributes in the group
|
|
231
|
+
const pollRespMetadata = deviceState.deviceTypeInfo!.resp!;
|
|
232
|
+
|
|
233
|
+
// Loop
|
|
234
|
+
while (msgBufIdx < msgBytes.length) {
|
|
235
|
+
|
|
236
|
+
const curTimelineLen = deviceState.deviceTimeline.timestampsUs.length;
|
|
237
|
+
const newMsgBufIdx = this._attributeHandler.processMsgAttrGroup(msgBuffer, msgBufIdx,
|
|
238
|
+
deviceState.deviceTimeline, pollRespMetadata,
|
|
239
|
+
deviceState.deviceAttributes,
|
|
240
|
+
this._maxDatapointsToStore);
|
|
241
|
+
if (newMsgBufIdx < 0)
|
|
242
|
+
break;
|
|
243
|
+
msgBufIdx = newMsgBufIdx;
|
|
244
|
+
if (deviceState.deviceTimeline.timestampsUs.length !== curTimelineLen) {
|
|
245
|
+
deviceState.stateChanged = true;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
// Check for devices that have not been updated for a while
|
|
253
|
+
if (this._removeDevicesFlag) {
|
|
254
|
+
const nowTime = Date.now();
|
|
255
|
+
Object.entries(this._deviceLastUpdateTime).forEach(([deviceKey, lastUpdateTime]) => {
|
|
256
|
+
if ((nowTime - lastUpdateTime) > this._removeDevicesTimeMs) {
|
|
257
|
+
delete this._devicesState[deviceKey];
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Process the callback
|
|
263
|
+
this.processStateCallback();
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
////////////////////////////////////////////////////////////////////////////
|
|
267
|
+
// Process state change callback
|
|
268
|
+
////////////////////////////////////////////////////////////////////////////
|
|
269
|
+
|
|
270
|
+
private processStateCallback() {
|
|
271
|
+
|
|
272
|
+
// Iterate over the devices
|
|
273
|
+
Object.entries(this._devicesState).forEach(([deviceKey, deviceState]) => {
|
|
274
|
+
|
|
275
|
+
// Check if device record is new
|
|
276
|
+
if (deviceState.deviceIsNew) {
|
|
277
|
+
if (this._callbackNewDevice) {
|
|
278
|
+
this._callbackNewDevice(
|
|
279
|
+
deviceKey,
|
|
280
|
+
deviceState
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
deviceState.deviceIsNew = false;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Iterate over the attributes
|
|
287
|
+
Object.entries(deviceState.deviceAttributes).forEach(([_attrKey, attrState]) => {
|
|
288
|
+
if (attrState.newAttribute) {
|
|
289
|
+
if (this._callbackNewDeviceAttribute) {
|
|
290
|
+
this._callbackNewDeviceAttribute(
|
|
291
|
+
deviceKey,
|
|
292
|
+
attrState
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
attrState.newAttribute = false;
|
|
296
|
+
}
|
|
297
|
+
if (attrState.newData) {
|
|
298
|
+
if (this._callbackNewAttributeData) {
|
|
299
|
+
this._callbackNewAttributeData(
|
|
300
|
+
deviceKey,
|
|
301
|
+
attrState
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
attrState.newData = false;
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
////////////////////////////////////////////////////////////////////////////
|
|
311
|
+
// Get device type info
|
|
312
|
+
////////////////////////////////////////////////////////////////////////////
|
|
313
|
+
|
|
314
|
+
private async getDeviceTypeInfo(busName: string, _devAddr: string, deviceType: string): Promise<DeviceTypeInfo | undefined> {
|
|
315
|
+
|
|
316
|
+
// Check if already in the cache
|
|
317
|
+
if (deviceType in this._cachedDeviceTypeRecs) {
|
|
318
|
+
return this._cachedDeviceTypeRecs[deviceType];
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Check if we have tried to get device info previously (and failed presumably since it isn't in the cache)
|
|
322
|
+
if (deviceType in this._cachedDeviceTypePreviousAttemptTimes) {
|
|
323
|
+
// Check if we should retry
|
|
324
|
+
if ((Date.now() - this._cachedDeviceTypePreviousAttemptTimes[deviceType]) < this._minTimeBetweenDeviceTypeInfoRetrievalMs) {
|
|
325
|
+
return undefined;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
this._cachedDeviceTypePreviousAttemptTimes[deviceType] = Date.now();
|
|
329
|
+
|
|
330
|
+
// Get the device type info from the server
|
|
331
|
+
try {
|
|
332
|
+
// Form the request
|
|
333
|
+
const cmd = "devman/typeinfo?bus=" + busName + "&type=" + deviceType;
|
|
334
|
+
|
|
335
|
+
// Get the msg handler
|
|
336
|
+
const msgHandler = this._systemUtils?.getMsgHandler();
|
|
337
|
+
if (msgHandler) {
|
|
338
|
+
const msgRslt = await msgHandler.sendRICRESTURL<RaftDevTypeInfoResponse>(cmd);
|
|
339
|
+
if (msgRslt.rslt === "ok") {
|
|
340
|
+
this._cachedDeviceTypeRecs[deviceType] = msgRslt.devinfo;
|
|
341
|
+
return msgRslt.devinfo
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return undefined;
|
|
345
|
+
} catch (error) {
|
|
346
|
+
console.error(`DeviceManager getDeviceTypeInfo error ${error}`);
|
|
347
|
+
return undefined;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
////////////////////////////////////////////////////////////////////////////
|
|
352
|
+
// Send action to device
|
|
353
|
+
////////////////////////////////////////////////////////////////////////////
|
|
354
|
+
|
|
355
|
+
public async sendAction(deviceKey: string, action: DeviceTypeAction, data: DataType[]): Promise<boolean> {
|
|
356
|
+
// console.log(`DeviceManager sendAction ${deviceKey} action name ${action.n} value ${value} prefix ${action.w}`);
|
|
357
|
+
|
|
358
|
+
// Form the write bytes
|
|
359
|
+
let writeBytes = action.t ? struct.pack(action.t, data) : Buffer.from([]);
|
|
360
|
+
|
|
361
|
+
// Convert to hex string
|
|
362
|
+
let writeHexStr = Buffer.from(writeBytes).toString('hex');
|
|
363
|
+
|
|
364
|
+
// Add prefix
|
|
365
|
+
writeHexStr = action.w + writeHexStr;
|
|
366
|
+
|
|
367
|
+
// Separate the bus and address in the deviceKey (_ char)
|
|
368
|
+
const devBus = deviceKey.split("_")[0]
|
|
369
|
+
const devAddr = deviceKey.split("_")[1]
|
|
370
|
+
|
|
371
|
+
// Send the action to the server
|
|
372
|
+
const cmd = "devman/cmdraw?bus=" + devBus + "&addr=" + devAddr + "&hexWr=" + writeHexStr;
|
|
373
|
+
|
|
374
|
+
console.log(`DeviceManager deviceKey ${deviceKey} action name ${action.n} value ${data} prefix ${action.w} sendAction ${cmd}`);
|
|
375
|
+
|
|
376
|
+
// Send the command
|
|
377
|
+
try {
|
|
378
|
+
|
|
379
|
+
// Get the msg handler
|
|
380
|
+
const msgHandler = this._systemUtils?.getMsgHandler();
|
|
381
|
+
if (msgHandler) {
|
|
382
|
+
const msgRslt = await msgHandler.sendRICRESTURL<RaftOKFail>(cmd);
|
|
383
|
+
return msgRslt.isOk();
|
|
384
|
+
}
|
|
385
|
+
return false;
|
|
386
|
+
} catch (error) {
|
|
387
|
+
console.warn(`DeviceManager sendAction error ${error}`);
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
////////////////////////////////////////////////////////////////////////////
|
|
393
|
+
// Send a compound action to the device
|
|
394
|
+
////////////////////////////////////////////////////////////////////////////
|
|
395
|
+
|
|
396
|
+
public async sendCompoundAction(deviceKey: string, action: DeviceTypeAction, data: DataType[][]): Promise<boolean> {
|
|
397
|
+
// console.log(`DeviceManager sendAction ${deviceKey} action name ${action.n} value ${value} prefix ${action.w}`);
|
|
398
|
+
|
|
399
|
+
// Check if all data to be sent at once
|
|
400
|
+
if (action.concat) {
|
|
401
|
+
// Form a single list by flattening data
|
|
402
|
+
let dataToWrite: DataType[] = [];
|
|
403
|
+
for (let dataIdx = 0; dataIdx < data.length; dataIdx++) {
|
|
404
|
+
dataToWrite = dataToWrite.concat(data[dataIdx]);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Use sendAction to send this
|
|
408
|
+
return await this.sendAction(deviceKey, action, dataToWrite);
|
|
409
|
+
} else {
|
|
410
|
+
// Iterate over the data
|
|
411
|
+
let allOk = true;
|
|
412
|
+
for (let dataIdx = 0; dataIdx < data.length; dataIdx++) {
|
|
413
|
+
|
|
414
|
+
// Create the data to write by prepending the index to the data for this index
|
|
415
|
+
let dataToWrite = [dataIdx as DataType].concat(data[dataIdx]);
|
|
416
|
+
|
|
417
|
+
// Use sendAction to send this
|
|
418
|
+
allOk = allOk && await this.sendAction(deviceKey, action, dataToWrite);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return false;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
////////////////////////////////////////////////////////////////////////////
|
|
425
|
+
// Convert hex to bytes
|
|
426
|
+
////////////////////////////////////////////////////////////////////////////
|
|
427
|
+
|
|
428
|
+
private hexToBytes(hex: string): Uint8Array {
|
|
429
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
430
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
431
|
+
bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
|
|
432
|
+
}
|
|
433
|
+
return bytes;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
//
|
|
3
|
+
// RaftDeviceMgrIF.ts
|
|
4
|
+
// Interface to devices state
|
|
5
|
+
//
|
|
6
|
+
// Rob Dobson (C) 2024
|
|
7
|
+
//
|
|
8
|
+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
9
|
+
|
|
10
|
+
import { DataType } from "python-struct";
|
|
11
|
+
import { DeviceTypeAction } from "./RaftDeviceInfo";
|
|
12
|
+
import { DeviceAttributeState, DevicesState, DeviceState } from "./RaftDeviceStates";
|
|
13
|
+
|
|
14
|
+
export default interface RaftDeviceMgrIF {
|
|
15
|
+
|
|
16
|
+
// Get state of devices
|
|
17
|
+
getDevicesState(): DevicesState;
|
|
18
|
+
getDeviceState(deviceKey: string): DeviceState;
|
|
19
|
+
|
|
20
|
+
// Callbacks
|
|
21
|
+
onNewDevice(callback: (deviceKey: string, state: DeviceState) => void): void;
|
|
22
|
+
onNewDeviceAttribute(callback: (deviceKey: string, attrState: DeviceAttributeState) => void): void;
|
|
23
|
+
onNewAttributeData(callback: (deviceKey: string, attrState: DeviceAttributeState) => void): void;
|
|
24
|
+
|
|
25
|
+
// Send action to device
|
|
26
|
+
sendAction(deviceKey: string, action: DeviceTypeAction, data: DataType[]): void;
|
|
27
|
+
sendCompoundAction(deviceKey: string, action: DeviceTypeAction, data: DataType[][]): void;
|
|
28
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
//
|
|
3
|
+
// RaftDeviceMsg
|
|
4
|
+
// Device message for Raft devices
|
|
5
|
+
//
|
|
6
|
+
// Rob Dobson (C) 2024
|
|
7
|
+
//
|
|
8
|
+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
9
|
+
|
|
10
|
+
export interface DeviceMsgJsonElem {
|
|
11
|
+
[attrGroupName: string]: string | number | boolean; // Attribute group name and value
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface DeviceMsgJsonBus {
|
|
15
|
+
[devAddr: string]: DeviceMsgJsonElem;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface DeviceMsgJson {
|
|
19
|
+
[busName: string]: DeviceMsgJsonBus;
|
|
20
|
+
}
|