motion-master-client 0.0.21 → 0.0.22
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/.babelrc +3 -0
- package/.eslintrc.json +18 -0
- package/jest.config.ts +16 -0
- package/motion-master.proto +1822 -0
- package/package.json +2 -17
- package/project.json +45 -0
- package/src/lib/cia402.spec.ts +77 -0
- package/src/lib/cia402.ts +414 -0
- package/src/lib/config-file.spec.ts +114 -0
- package/src/lib/config-file.ts +63 -0
- package/src/lib/device-log-line.ts +5 -0
- package/src/lib/device-parameter.spec.ts +85 -0
- package/src/lib/device-parameter.ts +79 -0
- package/src/lib/device.ts +10 -0
- package/src/lib/hardware-description.spec.ts +253 -0
- package/src/lib/hardware-description.ts +129 -0
- package/src/lib/logger.ts +5 -0
- package/src/lib/monitoring-config.ts +6 -0
- package/src/lib/{monitoring-entry.d.ts → monitoring-entry.ts} +5 -4
- package/src/lib/motion-master-client.ts +221 -0
- package/src/lib/motion-master-pub-sub-client.ts +95 -0
- package/src/lib/motion-master-pub-sub-socket.ts +40 -0
- package/src/lib/motion-master-pub-sub-web-socket.ts +78 -0
- package/src/lib/motion-master-pub-sub-worker-socket.ts +51 -0
- package/src/lib/motion-master-req-res-client.spec.ts +740 -0
- package/src/lib/motion-master-req-res-client.ts +2120 -0
- package/src/lib/motion-master-req-res-socket.ts +62 -0
- package/src/lib/motion-master-req-res-web-socket.ts +124 -0
- package/src/lib/motion-master-req-res-worker-socket.ts +87 -0
- package/src/lib/motion-master.proto.js +2 -2
- package/src/lib/operators.ts +90 -0
- package/src/lib/options.ts +12 -0
- package/src/lib/parameter.spec.ts +160 -0
- package/src/lib/parameter.ts +170 -0
- package/src/lib/product-id-range.ts +8 -0
- package/src/lib/request-status-resolver.ts +403 -0
- package/src/lib/system-log-line.ts +9 -0
- package/src/lib/{types.d.ts → types.ts} +74 -143
- package/src/lib/urls.ts +6 -0
- package/src/lib/util.ts +305 -0
- package/tsconfig.json +23 -0
- package/tsconfig.lib.json +10 -0
- package/tsconfig.spec.json +20 -0
- package/typedoc.json +10 -0
- package/src/index.js +0 -29
- package/src/index.js.map +0 -1
- package/src/lib/cia402.d.ts +0 -182
- package/src/lib/cia402.js +0 -392
- package/src/lib/cia402.js.map +0 -1
- package/src/lib/config-file.d.ts +0 -13
- package/src/lib/config-file.js +0 -50
- package/src/lib/config-file.js.map +0 -1
- package/src/lib/device-log-line.d.ts +0 -5
- package/src/lib/device-log-line.js +0 -3
- package/src/lib/device-log-line.js.map +0 -1
- package/src/lib/device-parameter.d.ts +0 -56
- package/src/lib/device-parameter.js +0 -39
- package/src/lib/device-parameter.js.map +0 -1
- package/src/lib/device.d.ts +0 -9
- package/src/lib/device.js +0 -3
- package/src/lib/device.js.map +0 -1
- package/src/lib/hardware-description.d.ts +0 -41
- package/src/lib/hardware-description.js +0 -94
- package/src/lib/hardware-description.js.map +0 -1
- package/src/lib/logger.d.ts +0 -1
- package/src/lib/logger.js +0 -8
- package/src/lib/logger.js.map +0 -1
- package/src/lib/monitoring-config.d.ts +0 -6
- package/src/lib/monitoring-config.js +0 -3
- package/src/lib/monitoring-config.js.map +0 -1
- package/src/lib/monitoring-entry.js +0 -3
- package/src/lib/monitoring-entry.js.map +0 -1
- package/src/lib/motion-master-client.d.ts +0 -52
- package/src/lib/motion-master-client.js +0 -151
- package/src/lib/motion-master-client.js.map +0 -1
- package/src/lib/motion-master-pub-sub-client.d.ts +0 -16
- package/src/lib/motion-master-pub-sub-client.js +0 -68
- package/src/lib/motion-master-pub-sub-client.js.map +0 -1
- package/src/lib/motion-master-pub-sub-socket.d.ts +0 -34
- package/src/lib/motion-master-pub-sub-socket.js +0 -3
- package/src/lib/motion-master-pub-sub-socket.js.map +0 -1
- package/src/lib/motion-master-pub-sub-web-socket.d.ts +0 -14
- package/src/lib/motion-master-pub-sub-web-socket.js +0 -67
- package/src/lib/motion-master-pub-sub-web-socket.js.map +0 -1
- package/src/lib/motion-master-pub-sub-worker-socket.d.ts +0 -14
- package/src/lib/motion-master-pub-sub-worker-socket.js +0 -42
- package/src/lib/motion-master-pub-sub-worker-socket.js.map +0 -1
- package/src/lib/motion-master-req-res-client.d.ts +0 -920
- package/src/lib/motion-master-req-res-client.js +0 -1680
- package/src/lib/motion-master-req-res-client.js.map +0 -1
- package/src/lib/motion-master-req-res-socket.d.ts +0 -52
- package/src/lib/motion-master-req-res-socket.js +0 -3
- package/src/lib/motion-master-req-res-socket.js.map +0 -1
- package/src/lib/motion-master-req-res-web-socket.d.ts +0 -24
- package/src/lib/motion-master-req-res-web-socket.js +0 -99
- package/src/lib/motion-master-req-res-web-socket.js.map +0 -1
- package/src/lib/motion-master-req-res-worker-socket.d.ts +0 -20
- package/src/lib/motion-master-req-res-worker-socket.js +0 -69
- package/src/lib/motion-master-req-res-worker-socket.js.map +0 -1
- package/src/lib/operators.d.ts +0 -18
- package/src/lib/operators.js +0 -76
- package/src/lib/operators.js.map +0 -1
- package/src/lib/options.d.ts +0 -10
- package/src/lib/options.js +0 -14
- package/src/lib/options.js.map +0 -1
- package/src/lib/parameter.d.ts +0 -72
- package/src/lib/parameter.js +0 -119
- package/src/lib/parameter.js.map +0 -1
- package/src/lib/product-id-range.d.ts +0 -7
- package/src/lib/product-id-range.js +0 -12
- package/src/lib/product-id-range.js.map +0 -1
- package/src/lib/request-status-resolver.d.ts +0 -4
- package/src/lib/request-status-resolver.js +0 -345
- package/src/lib/request-status-resolver.js.map +0 -1
- package/src/lib/system-log-line.d.ts +0 -9
- package/src/lib/system-log-line.js +0 -3
- package/src/lib/system-log-line.js.map +0 -1
- package/src/lib/types.js +0 -28
- package/src/lib/types.js.map +0 -1
- package/src/lib/urls.d.ts +0 -3
- package/src/lib/urls.js +0 -10
- package/src/lib/urls.js.map +0 -1
- package/src/lib/util.d.ts +0 -40
- package/src/lib/util.js +0 -316
- package/src/lib/util.js.map +0 -1
- /package/src/{index.d.ts → index.ts} +0 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { BehaviorSubject, Observable } from "rxjs";
|
|
2
|
+
import { IMotionMasterMessage } from "./types";
|
|
3
|
+
|
|
4
|
+
export interface MotionMasterReqResSocket {
|
|
5
|
+
/**
|
|
6
|
+
* Emits a boolean value when socket gets opened or closed.
|
|
7
|
+
*/
|
|
8
|
+
readonly opened$: BehaviorSubject<boolean>;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Motion Master is considered alive when it sends messages in regular time interval.
|
|
12
|
+
*/
|
|
13
|
+
readonly alive$: BehaviorSubject<boolean>;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Decoded message instances coming from Motion Master.
|
|
17
|
+
*/
|
|
18
|
+
readonly message$: Observable<IMotionMasterMessage>;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* URL set in call to open.
|
|
22
|
+
*/
|
|
23
|
+
get url(): string | undefined;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Send ping system messages to Motion Master with a fixed time delay between each call.
|
|
27
|
+
*/
|
|
28
|
+
get pingSystemInterval(): number | undefined;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* How long in milliseconds to consider Motion Master alive.
|
|
32
|
+
*/
|
|
33
|
+
get systemAliveTimeout(): number | undefined;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Open socket.
|
|
37
|
+
*
|
|
38
|
+
* The connected$ and eventually alive$ observables will emit true values.
|
|
39
|
+
*/
|
|
40
|
+
open(url: string, pingSystemInterval?: number, systemAliveTimeout?: number): void;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Close socket.
|
|
44
|
+
*
|
|
45
|
+
* The opened$ and alive$ observables will emit false values.
|
|
46
|
+
*/
|
|
47
|
+
close(): void;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Reopen socket.
|
|
51
|
+
*
|
|
52
|
+
* Reopen if closed using the same url, pingSystemInterval, and systemAliveTimeout previously set in open.
|
|
53
|
+
*/
|
|
54
|
+
reopen(): void;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Send an instance of a message.
|
|
58
|
+
*
|
|
59
|
+
* Subscribe to the message$ observable in order to receive the response messages.
|
|
60
|
+
*/
|
|
61
|
+
send(message: IMotionMasterMessage): void;
|
|
62
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { BehaviorSubject, filter, interval, map, Subject, Subscription, tap } from "rxjs";
|
|
2
|
+
import { webSocket, WebSocketSubject, WebSocketSubjectConfig } from "rxjs/webSocket";
|
|
3
|
+
import { logger } from "./logger";
|
|
4
|
+
import { MotionMasterReqResSocket } from "./motion-master-req-res-socket";
|
|
5
|
+
import { IMotionMasterMessage, MotionMasterMessage } from "./types";
|
|
6
|
+
import { convertMotionMasterMessageToLoggerContext, createPlainObjectFromMotionMasterMessage } from "./util";
|
|
7
|
+
|
|
8
|
+
export class MotionMasterReqResWebSocket implements MotionMasterReqResSocket {
|
|
9
|
+
|
|
10
|
+
readonly opened$ = new BehaviorSubject<boolean>(false);
|
|
11
|
+
|
|
12
|
+
readonly alive$ = new BehaviorSubject<boolean>(false);
|
|
13
|
+
|
|
14
|
+
readonly message$ = new Subject<IMotionMasterMessage>();
|
|
15
|
+
|
|
16
|
+
private aliveTimeoutId = 0;
|
|
17
|
+
|
|
18
|
+
private pingSystemObserver = { next: () => this.send({ request: { pingSystem: {} } }) };
|
|
19
|
+
|
|
20
|
+
private pingSystemSubscription = new Subscription();
|
|
21
|
+
|
|
22
|
+
private webSocket$?: WebSocketSubject<Uint8Array>;
|
|
23
|
+
|
|
24
|
+
private _url?: string;
|
|
25
|
+
private _pingSystemInterval?: number;
|
|
26
|
+
private _systemAliveTimeout?: number;
|
|
27
|
+
|
|
28
|
+
get url(): string | undefined {
|
|
29
|
+
return this._url;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
get pingSystemInterval(): number | undefined {
|
|
33
|
+
return this._pingSystemInterval;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
get systemAliveTimeout(): number | undefined {
|
|
37
|
+
return this._systemAliveTimeout;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
open(url: string, pingSystemInterval = 250, systemAliveTimeout = 1000): void {
|
|
41
|
+
if (this.opened$.getValue() === true) {
|
|
42
|
+
throw new Error('MotionMasterReqResWebSocket is already opened!');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
this._url = url;
|
|
46
|
+
this._pingSystemInterval = pingSystemInterval;
|
|
47
|
+
this._systemAliveTimeout = systemAliveTimeout;
|
|
48
|
+
|
|
49
|
+
this.webSocket$ = this.createWebSocket(url, pingSystemInterval);
|
|
50
|
+
|
|
51
|
+
this.webSocket$?.pipe(
|
|
52
|
+
map((data: Uint8Array) => MotionMasterMessage.decode(data)),
|
|
53
|
+
tap(() => this.keepalive(systemAliveTimeout)),
|
|
54
|
+
filter((message) => !(message.status?.systemPong)),
|
|
55
|
+
map(message => createPlainObjectFromMotionMasterMessage(message)),
|
|
56
|
+
tap((message) => {
|
|
57
|
+
const context = convertMotionMasterMessageToLoggerContext(message);
|
|
58
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
59
|
+
logger.info(context as any, `Received ${context.name}`);
|
|
60
|
+
}),
|
|
61
|
+
).subscribe({
|
|
62
|
+
next: (message) => this.message$.next(message),
|
|
63
|
+
error: (err) => {
|
|
64
|
+
console.error(err);
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
close(): void {
|
|
70
|
+
clearTimeout(this.aliveTimeoutId);
|
|
71
|
+
this.pingSystemSubscription.unsubscribe();
|
|
72
|
+
this.webSocket$?.unsubscribe();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
reopen() {
|
|
76
|
+
if (this.url && this.opened$.value === false) {
|
|
77
|
+
this.open(this.url, this.pingSystemInterval, this.systemAliveTimeout);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
send(message: IMotionMasterMessage): void {
|
|
82
|
+
if (!message.request?.pingSystem) {
|
|
83
|
+
const context = convertMotionMasterMessageToLoggerContext(message);
|
|
84
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
85
|
+
logger.info(context as any, `Send ${context.name}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
this.webSocket$?.next(MotionMasterMessage.encode(message).finish());
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
private createWebSocket(url: string, pingSystemInterval = 250) {
|
|
92
|
+
const webSocketConfig: WebSocketSubjectConfig<Uint8Array> = {
|
|
93
|
+
binaryType: 'arraybuffer',
|
|
94
|
+
closeObserver: {
|
|
95
|
+
next: () => {
|
|
96
|
+
this.opened$.next(false);
|
|
97
|
+
logger.info(`Connection closed ${url}`);
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
deserializer: (e: MessageEvent) => new Uint8Array(e.data as unknown as Iterable<number>),
|
|
101
|
+
openObserver: {
|
|
102
|
+
next: () => {
|
|
103
|
+
this.pingSystemSubscription = interval(pingSystemInterval)
|
|
104
|
+
.subscribe(this.pingSystemObserver);
|
|
105
|
+
this.opened$.next(true);
|
|
106
|
+
logger.info(`Connection opened ${url}`);
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
serializer: (value: Uint8Array) => value,
|
|
110
|
+
url,
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
return webSocket(webSocketConfig);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private keepalive(systemAliveTimeout = 1000) {
|
|
117
|
+
if (this.alive$.getValue() === false) {
|
|
118
|
+
this.alive$.next(true);
|
|
119
|
+
}
|
|
120
|
+
clearTimeout(this.aliveTimeoutId);
|
|
121
|
+
this.aliveTimeoutId = setTimeout(() => this.alive$.next(false), systemAliveTimeout) as unknown as number;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { BehaviorSubject, Subject } from "rxjs";
|
|
2
|
+
import { logger } from "./logger";
|
|
3
|
+
import { MotionMasterReqResSocket } from "./motion-master-req-res-socket";
|
|
4
|
+
import { IMotionMasterMessage } from "./types";
|
|
5
|
+
import { convertMotionMasterMessageToLoggerContext } from "./util";
|
|
6
|
+
|
|
7
|
+
export class MotionMasterReqResWorkerSocket implements MotionMasterReqResSocket {
|
|
8
|
+
|
|
9
|
+
readonly opened$ = new BehaviorSubject<boolean>(false);
|
|
10
|
+
|
|
11
|
+
readonly alive$ = new BehaviorSubject<boolean>(false);
|
|
12
|
+
|
|
13
|
+
readonly message$ = new Subject<IMotionMasterMessage>();
|
|
14
|
+
|
|
15
|
+
private _url?: string;
|
|
16
|
+
private _pingSystemInterval?: number;
|
|
17
|
+
private _systemAliveTimeout?: number;
|
|
18
|
+
|
|
19
|
+
constructor(
|
|
20
|
+
public readonly worker: Worker,
|
|
21
|
+
) { }
|
|
22
|
+
|
|
23
|
+
get url(): string | undefined {
|
|
24
|
+
return this._url;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get pingSystemInterval(): number | undefined {
|
|
28
|
+
return this._pingSystemInterval;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get systemAliveTimeout(): number | undefined {
|
|
32
|
+
return this._systemAliveTimeout;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
open(url: string, pingSystemInterval = 250, systemAliveTimeout = 1000): void {
|
|
36
|
+
if (this.opened$.getValue() === true) {
|
|
37
|
+
throw new Error('MotionMasterReqResWorkerSocket is already opened!');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
this._url = url;
|
|
41
|
+
this._pingSystemInterval = pingSystemInterval;
|
|
42
|
+
this._systemAliveTimeout = systemAliveTimeout;
|
|
43
|
+
|
|
44
|
+
this.worker.onmessage = ({ data }) => {
|
|
45
|
+
if ('opened' in data) {
|
|
46
|
+
const { opened } = data;
|
|
47
|
+
this.opened$.next(opened);
|
|
48
|
+
logger.info(opened ? `Opened req/res 🔌 ${url}` : `Closed req/res 🔌 ${url}`);
|
|
49
|
+
} else if ('alive' in data) {
|
|
50
|
+
const { alive } = data;
|
|
51
|
+
this.alive$.next(alive);
|
|
52
|
+
logger.info(alive ? `System is alive 💓` : 'System is as dead as 🦤');
|
|
53
|
+
} else if ('message' in data) {
|
|
54
|
+
const { message } = data;
|
|
55
|
+
|
|
56
|
+
const context = convertMotionMasterMessageToLoggerContext(message);
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
58
|
+
logger.info(context as any, `Received ${context.name}`);
|
|
59
|
+
|
|
60
|
+
this.message$.next(message);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
this.worker.postMessage({
|
|
65
|
+
open: { url, pingSystemInterval, systemAliveTimeout },
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
reopen() {
|
|
70
|
+
if (this.url && this.opened$.value === false) {
|
|
71
|
+
this.open(this.url, this.pingSystemInterval, this.systemAliveTimeout);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
close(): void {
|
|
76
|
+
this.worker.postMessage({ close: true });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
send(message: IMotionMasterMessage): void {
|
|
80
|
+
const context = convertMotionMasterMessageToLoggerContext(message);
|
|
81
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
82
|
+
logger.info(context as any, `Send ${context.name}`);
|
|
83
|
+
|
|
84
|
+
this.worker.postMessage({ message });
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
var $protobuf = require("protobufjs/minimal");
|
|
5
5
|
|
|
6
6
|
// @ts-expect-error Explicitly disable long.js support
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
$protobuf.util.Long = undefined;
|
|
8
|
+
$protobuf.configure();
|
|
9
9
|
|
|
10
10
|
// Common aliases
|
|
11
11
|
const $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { pipe, filter, map, timeout, takeWhile } from 'rxjs';
|
|
2
|
+
import { getParameterValue } from './util';
|
|
3
|
+
import { requestStatusResolver } from './request-status-resolver';
|
|
4
|
+
import { IMotionMasterMessage, MotionMasterMessage, ParameterValueType, StatusKey } from './types';
|
|
5
|
+
import { Parameter } from './parameter';
|
|
6
|
+
|
|
7
|
+
export function selectMotionMasterMessageStatusByMessageId<T>(key: StatusKey, id?: string) {
|
|
8
|
+
return pipe(
|
|
9
|
+
filter((message: IMotionMasterMessage) => message.id === id),
|
|
10
|
+
map((message) => {
|
|
11
|
+
// Handling the special case when Motion Master sends SystemEvent instead of e.g. DeviceParameterInfo status for
|
|
12
|
+
// GetDeviceParameterInfo request message. This typically happens when request contains an invalid device address.
|
|
13
|
+
if (message.status?.systemEvent && key !== 'systemEvent') {
|
|
14
|
+
if (message.status.systemEvent.error) {
|
|
15
|
+
throw new Error(`Error selecting message: ${message.status.systemEvent.error.message ?? ''}`);
|
|
16
|
+
} else {
|
|
17
|
+
throw new Error(`Error selecting message. Received System Event instead of "${key.toString()}": ${JSON.stringify(message)}`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return message.status?.[key] as T;
|
|
21
|
+
}),
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function extendStatus<T>(data: { statusKey: StatusKey, messageId: string }) {
|
|
26
|
+
return pipe(
|
|
27
|
+
map((status: T) => {
|
|
28
|
+
const { statusKey, messageId } = data;
|
|
29
|
+
const request = requestStatusResolver[statusKey]?.<T>(status);
|
|
30
|
+
return { ...status, messageId, request };
|
|
31
|
+
}),
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function transformMotionMasterMessageToStatus<T>(statusKey: StatusKey, requestTimeout: number, messageId: string) {
|
|
36
|
+
if (typeof requestTimeout !== 'number') {
|
|
37
|
+
throw new Error(`Invalid requestTimeout=${requestTimeout} provided for ${statusKey}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return pipe(
|
|
41
|
+
selectMotionMasterMessageStatusByMessageId<T>(statusKey, messageId),
|
|
42
|
+
timeout(requestTimeout),
|
|
43
|
+
extendStatus({ statusKey, messageId }),
|
|
44
|
+
takeWhile((status) => status.request !== 'succeeded' && status.request !== 'failed', true),
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function selectMotionMasterMessageByTopic<T>(topic: string) {
|
|
49
|
+
return pipe(
|
|
50
|
+
filter(([t]: [string, T]) => t === topic),
|
|
51
|
+
map(([, data]) => data),
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function selectMotionMasterMessageStatusByKey<T>(key: keyof MotionMasterMessage.IStatus) {
|
|
56
|
+
return pipe(
|
|
57
|
+
filter((message: IMotionMasterMessage) => !!(message.status && message.status[key])),
|
|
58
|
+
map((message) => message.status?.[key] as T),
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function mapMonitoringParameterValuesStatusMessageToParameterValues() {
|
|
63
|
+
return pipe(
|
|
64
|
+
map((message: IMotionMasterMessage) => {
|
|
65
|
+
if (message.status?.monitoringParameterValues) {
|
|
66
|
+
const { timestamp, deviceParameterValues } = message.status.monitoringParameterValues;
|
|
67
|
+
return [
|
|
68
|
+
timestamp,
|
|
69
|
+
...(deviceParameterValues?.parameterValues?.map((parameterValue) => getParameterValue(parameterValue)) ?? []),
|
|
70
|
+
] as ParameterValueType[];
|
|
71
|
+
}
|
|
72
|
+
return [];
|
|
73
|
+
}),
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function mapMonitoringParameterValuesStatusMessageToDeviceParameters() {
|
|
78
|
+
return pipe(
|
|
79
|
+
map((message: IMotionMasterMessage) => {
|
|
80
|
+
if (message.status?.monitoringParameterValues) {
|
|
81
|
+
const { timestamp, deviceParameterValues } = message.status.monitoringParameterValues;
|
|
82
|
+
return [
|
|
83
|
+
timestamp,
|
|
84
|
+
...deviceParameterValues?.parameterValues ?? [],
|
|
85
|
+
] as Parameter[];
|
|
86
|
+
}
|
|
87
|
+
return [];
|
|
88
|
+
}),
|
|
89
|
+
);
|
|
90
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { MotionMasterMessage } from './types';
|
|
2
|
+
|
|
3
|
+
export const parameterValueTypeOptions = {
|
|
4
|
+
'intValue': 'intValue',
|
|
5
|
+
'uintValue': 'uintValue',
|
|
6
|
+
'floatValue': 'floatValue',
|
|
7
|
+
'stringValue': 'stringValue',
|
|
8
|
+
'rawValue': 'rawValue',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const ethercatNetworkStateOptions = MotionMasterMessage.Status.EthercatNetworkState.State;
|
|
12
|
+
export const positionControllerTypeOptions = MotionMasterMessage.Request.ComputeAutoTuningGains.PositionParameters.ControllerType;
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { differenceParameters, intersectionParameters, makeParameterId, splitParameterId } from "./parameter";
|
|
2
|
+
|
|
3
|
+
describe('parameter', () => {
|
|
4
|
+
|
|
5
|
+
describe('makeParameterId', () => {
|
|
6
|
+
|
|
7
|
+
test.each<[[(number | null | undefined), (number | null | undefined)], string]>([
|
|
8
|
+
[[0x1234, 123], '0x1234:7B'],
|
|
9
|
+
[[23, 23], '0x0017:17'],
|
|
10
|
+
[[0, 0], '0x0000:00'],
|
|
11
|
+
[[0x2000, undefined], '0x2000:00'],
|
|
12
|
+
[[0x2003, null], '0x2003:00'],
|
|
13
|
+
[[0x10000, 3], '0x00010000:03'],
|
|
14
|
+
[[0x100F0, undefined], '0x000100F0:00'],
|
|
15
|
+
])('should for tuple %j return "%s"', (tuple, expected) => {
|
|
16
|
+
const result = makeParameterId(tuple);
|
|
17
|
+
|
|
18
|
+
expect(result).toBe(expected);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test.each([
|
|
22
|
+
[{}, '0x0000:00'],
|
|
23
|
+
[{ index: 0x2004, subindex: 4 }, '0x2004:04'],
|
|
24
|
+
[{ index: 0x1024 }, '0x1024:00'],
|
|
25
|
+
])('should for parameter %j return "%s"', (parameter, expected) => {
|
|
26
|
+
const result = makeParameterId(parameter);
|
|
27
|
+
|
|
28
|
+
expect(result).toBe(expected);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test.each([
|
|
32
|
+
[0x1234, 123, '0x1234:7B'],
|
|
33
|
+
[23, 23, '0x0017:17'],
|
|
34
|
+
[0, 0, '0x0000:00'],
|
|
35
|
+
[0x2000, undefined, '0x2000:00'],
|
|
36
|
+
[0x2003, null, '0x2003:00'],
|
|
37
|
+
[0x10000, 3, '0x00010000:03'],
|
|
38
|
+
[0x100F0, undefined, '0x000100F0:00'],
|
|
39
|
+
])('should for index %d and subindex %d return "%s"', (index, subindex, expected) => {
|
|
40
|
+
const result = makeParameterId(index, subindex);
|
|
41
|
+
|
|
42
|
+
expect(result).toBe(expected);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should throw if index is less than 0', () => {
|
|
46
|
+
expect(() => {
|
|
47
|
+
makeParameterId(-123, 0);
|
|
48
|
+
}).toThrow();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should throw if subindex is less than 0', () => {
|
|
52
|
+
expect(() => {
|
|
53
|
+
makeParameterId(0x1024, -3);
|
|
54
|
+
}).toThrow();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe('splitParameterId', () => {
|
|
60
|
+
|
|
61
|
+
test.each([
|
|
62
|
+
['0x1234:7B', [4660, 123]],
|
|
63
|
+
['0x000100F0:00', [65776, 0]],
|
|
64
|
+
])('should for id "%s" return tuple %j', (id, expected) => {
|
|
65
|
+
const result = splitParameterId(id);
|
|
66
|
+
|
|
67
|
+
expect(result).toEqual(expected);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test.each([
|
|
71
|
+
['0x12:7B'],
|
|
72
|
+
['0x1234:F'],
|
|
73
|
+
['0x1234:FG'],
|
|
74
|
+
['0x1H34:FF'],
|
|
75
|
+
])('should throw error for id "%s"', (id) => {
|
|
76
|
+
expect(() => splitParameterId(id)).toThrow();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe('differenceParameters', () => {
|
|
82
|
+
it('should return an empty array if there are no differences', () => {
|
|
83
|
+
const parameters = differenceParameters(
|
|
84
|
+
[
|
|
85
|
+
{ index: 0x2030, subindex: 1 },
|
|
86
|
+
{ index: 0x2031, subindex: 1 },
|
|
87
|
+
],
|
|
88
|
+
[
|
|
89
|
+
{ index: 0x2030, subindex: 1 },
|
|
90
|
+
{ index: 0x2031, subindex: 1 },
|
|
91
|
+
],
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
expect(parameters).toEqual([]);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should return an array of differences', () => {
|
|
98
|
+
const parameters = differenceParameters(
|
|
99
|
+
[
|
|
100
|
+
{ index: 0x2030, subindex: 1 },
|
|
101
|
+
{ index: 0x2031, subindex: 1 },
|
|
102
|
+
{ index: 0x6040, subindex: 0 },
|
|
103
|
+
{ index: 0x6091, subindex: 0 },
|
|
104
|
+
],
|
|
105
|
+
[
|
|
106
|
+
{ index: 0x2031, subindex: 1 },
|
|
107
|
+
{ index: 0x6040, subindex: 0 },
|
|
108
|
+
{ index: 0x6041, subindex: 0 },
|
|
109
|
+
],
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
expect(parameters).toEqual([
|
|
113
|
+
{ index: 0x2030, subindex: 1 },
|
|
114
|
+
{ index: 0x6091, subindex: 0 },
|
|
115
|
+
]);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
fdescribe('intersectionParameters', () => {
|
|
120
|
+
it('should return full array if there are no differences', () => {
|
|
121
|
+
const parameters = intersectionParameters(
|
|
122
|
+
[
|
|
123
|
+
{ index: 0x2030, subindex: 1 },
|
|
124
|
+
{ index: 0x2031, subindex: 1 },
|
|
125
|
+
],
|
|
126
|
+
[
|
|
127
|
+
{ index: 0x2030, subindex: 1 },
|
|
128
|
+
{ index: 0x2031, subindex: 1 },
|
|
129
|
+
],
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
expect(parameters).toEqual([
|
|
133
|
+
{ index: 0x2030, subindex: 1 },
|
|
134
|
+
{ index: 0x2031, subindex: 1 },
|
|
135
|
+
]);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should return an array excluding differences', () => {
|
|
139
|
+
const parameters = intersectionParameters(
|
|
140
|
+
[
|
|
141
|
+
{ index: 0x2031, subindex: 1 },
|
|
142
|
+
{ index: 0x6040, subindex: 0 },
|
|
143
|
+
{ index: 0x6041, subindex: 0 },
|
|
144
|
+
],
|
|
145
|
+
[
|
|
146
|
+
{ index: 0x2030, subindex: 1 },
|
|
147
|
+
{ index: 0x2031, subindex: 1 },
|
|
148
|
+
{ index: 0x6040, subindex: 0 },
|
|
149
|
+
{ index: 0x6091, subindex: 0 },
|
|
150
|
+
],
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
expect(parameters).toEqual([
|
|
154
|
+
{ index: 0x2031, subindex: 1 },
|
|
155
|
+
{ index: 0x6040, subindex: 0 },
|
|
156
|
+
]);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
});
|