Skip to content

Commit 423fedd

Browse files
authored
Merge pull request #5 from CDPTechnologies/FixesForAddedEventSupport
Fixes for added event support
2 parents 6ef60ca + 2cf2c24 commit 423fedd

9 files changed

Lines changed: 350 additions & 195 deletions

File tree

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
node_modules/
2-
protos/
3-
helpers/
2+
protos/

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,13 @@ https://cdpstudio.com/manual/cdp/cdplogger/cdplogger-configuration-example.html
3939
2. Run the index.js file from the command line:
4040

4141
```bash
42-
node index.js
42+
node examples/index.js
4343
```
4444

4545
For usage related to events run:
4646

4747
```bash
48-
node event.js
48+
node examples/event.js
4949
```
5050

5151

client.js

Lines changed: 99 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
/* client.js */
12
const WebSocket = require('ws');
23
const root = require('./generated/containerPb.js');
34
const Container = root.DBMessaging.Protobuf.Container;
45
const CDPValueType = root.ICD.Protobuf.CDPValueType;
56

7+
/**
8+
* A client for interacting with CDP Logger or LogServer via WebSocket.
9+
*/
610
class Client {
711
/**
812
* @param {string} endpoint - The logger endpoint (e.g. "127.0.0.1:17000" or "ws://127.0.0.1:17000")
@@ -27,7 +31,7 @@ class Client {
2731
this.nameToId = {};
2832
this.idToName = {};
2933

30-
// New mapping for signal types.
34+
// Mapping for signal types (in case we need to interpret values).
3135
this.nameToType = {};
3236

3337
// Time-diff related
@@ -43,7 +47,13 @@ class Client {
4347

4448
/**
4549
* Enable or disable time synchronization.
46-
* @param {boolean} enable - If true, time sync is enabled; if false, time sync is disabled.
50+
*
51+
* Note:
52+
* Time sync is triggered on-demand (e.g., with the next request) or after a timeout.
53+
* Re-enabling time sync will automatically sync on the next operation.
54+
* For immediate sync, call `_updateTimeDiff()` explicitly.
55+
*
56+
* @param {boolean} enable - True to enable, false to disable time sync.
4757
*/
4858
setEnableTimeSync(enable) {
4959
this.enableTimeSync = enable;
@@ -174,17 +184,50 @@ class Client {
174184

175185
/**
176186
* Request events based on the provided query parameters.
187+
*
188+
* The `query.flags` field uses bitmask values similar to an enum:
189+
* 0 = None
190+
* 1 = NewestFirst
191+
* 2 = TimeRangeBeginExclusive
192+
* 4 = TimeRangeEndExclusive
193+
* 8 = UseLogStampForTimeRange
194+
*
195+
* The `query.senderConditions` field can be used to filter by event sender (Source).
196+
* The `query.dataConditions` field can be used to filter by data fields (key-value patterns).
197+
*
198+
* For additional information:
199+
* https://cdpstudio.com/manual/cdp/cdplogger/eventlogreader.html#Flags-enum
200+
* https://cdpstudio.com/manual/cdp/cdplogger/eventlogreader.html#cdp-event-code-flags
201+
*
202+
* We also support mapping the `evt.code` field to a human-readable string
203+
* with `getEventCodeDescription()`.
204+
*
177205
* @param {Object} query - An object matching the EventQuery schema.
178-
* For example:
206+
* Example:
179207
* {
180208
* timeRangeBegin: 1620000000,
181-
* timeRangeEnd: 1620003600,
182-
* codeMask: 0,
183-
* limit: 100,
184-
* offset: 0,
185-
* flags: 1
209+
* timeRangeEnd: 1620003600,
210+
* codeMask: 0xFFFFFFFF,
211+
* limit: 100,
212+
* offset: 0,
213+
* flags: 1, // e.g. 'NewestFirst'
214+
*
215+
* // Example conditions:
216+
* senderConditions: {
217+
* conditions: [
218+
* { value: "*TemperatureSensor*", type: 1 } // 1 = Wildcard
219+
* ]
220+
* },
221+
* dataConditions: {
222+
* pressure: {
223+
* conditions: [
224+
* { value: "high", type: 0 } // 0 = Exact
225+
* ]
226+
* }
227+
* }
186228
* }
187-
* @returns {Promise<Array>} Resolves with an array of events.
229+
*
230+
* @returns {Promise<Array>} Resolves with an array of events (each event includes a 'codeDescription').
188231
*/
189232
requestEvents(query) {
190233
this._timeRequest();
@@ -202,11 +245,41 @@ class Client {
202245
_sendEventsRequest(requestId, query) {
203246
const container = Container.create();
204247
container.messageType = Container.Type.eEventsRequest;
205-
container.eventsRequest = { requestId: requestId, query: query };
248+
container.eventsRequest = { requestId, query };
206249
const buffer = Container.encode(container).finish();
207250
this.ws.send(buffer);
208251
}
209252

253+
/**
254+
* Converts a numeric CDP event code into a descriptive string.
255+
* Multiple flags can be set simultaneously, so we combine them.
256+
*
257+
* Common codes (from the docs):
258+
* 0x1 = AlarmSet
259+
* 0x2 = AlarmClr
260+
* 0x4 = AlarmAck
261+
* 0x40 = AlarmReprise
262+
* 0x100 = SourceObjectUnavailable
263+
* 0x40000000 = NodeBoot
264+
*
265+
* @param {number} code - The event code from an eEventsResponse
266+
* @returns {string} - A human-readable combination of flags
267+
*/
268+
getEventCodeDescription(code) {
269+
const flags = [];
270+
if (code & 0x1) flags.push("AlarmSet");
271+
if (code & 0x2) flags.push("AlarmClr");
272+
if (code & 0x4) flags.push("AlarmAck");
273+
if (code & 0x40) flags.push("AlarmReprise");
274+
if (code & 0x100) flags.push("SourceObjectUnavailable");
275+
if (code & 0x40000000) flags.push("NodeBoot");
276+
277+
if (flags.length === 0) {
278+
flags.push("None");
279+
}
280+
return flags.join(" + ");
281+
}
282+
210283
_handleMessage(ws, message) {
211284
const data = Container.decode(new Uint8Array(message));
212285
this._parseMessage(data);
@@ -292,13 +365,13 @@ class Client {
292365
}
293366

294367
case Container.Type.eSignalDataResponse: {
295-
let dataPoints = [];
368+
const dataPoints = [];
296369
let index = 0;
297370
for (const row of data.signalDataResponse.row) {
298371
if (this.enableTimeSync) {
299372
data.signalDataResponse.criterion[index] += this.timeDiff;
300373
}
301-
let signalNames = [];
374+
const signalNames = [];
302375
for (const signalId of row.signalId) {
303376
signalNames.push(this.idToName[signalId]);
304377
}
@@ -310,7 +383,7 @@ class Client {
310383
);
311384
dataPoints.push({
312385
timestamp: data.signalDataResponse.criterion[index],
313-
value: value
386+
value
314387
});
315388
index++;
316389
}
@@ -323,6 +396,13 @@ class Client {
323396
}
324397

325398
case Container.Type.eEventsResponse: {
399+
// Optionally enrich each event with a human-readable code description:
400+
if (data.eventsResponse.events && data.eventsResponse.events.length > 0) {
401+
data.eventsResponse.events.forEach(evt => {
402+
evt.codeDescription = this.getEventCodeDescription(evt.code);
403+
});
404+
}
405+
326406
if (this.storedPromises[data.eventsResponse.requestId]) {
327407
const { resolve } = this.storedPromises[data.eventsResponse.requestId];
328408
delete this.storedPromises[data.eventsResponse.requestId];
@@ -452,11 +532,11 @@ class Client {
452532
});
453533
return promise;
454534
}
455-
535+
456536
_sendTimeRequest(requestId) {
457537
const container = Container.create();
458538
container.messageType = Container.Type.eTimeRequest;
459-
container.timeRequest = { requestId: requestId };
539+
container.timeRequest = { requestId };
460540
const buffer = Container.encode(container).finish();
461541
this.ws.send(buffer);
462542
}
@@ -484,15 +564,15 @@ class Client {
484564
_sendLoggedNodesRequest(requestId) {
485565
const container = Container.create();
486566
container.messageType = Container.Type.eSignalInfoRequest;
487-
container.signalInfoRequest = { requestId: requestId };
567+
container.signalInfoRequest = { requestId };
488568
const buffer = Container.encode(container).finish();
489569
this.ws.send(buffer);
490570
}
491571

492572
_sendLogLimitsRequest(requestId) {
493573
const container = Container.create();
494574
container.messageType = Container.Type.eCriterionLimitsRequest;
495-
container.criterionLimitsRequest = { requestId: requestId };
575+
container.criterionLimitsRequest = { requestId };
496576
const buffer = Container.encode(container).finish();
497577
this.ws.send(buffer);
498578
}
@@ -545,7 +625,7 @@ class Client {
545625
const container = Container.create();
546626
container.messageType = Container.Type.eSignalDataRequest;
547627
container.signalDataRequest = {
548-
requestId: requestId,
628+
requestId,
549629
signalId: nodeIds,
550630
numOfDatapoints: noOfDataPoints,
551631
criterionMin: this.enableTimeSync ? (startS - this.timeDiff) : startS,
@@ -558,7 +638,7 @@ class Client {
558638
_sendApiVersionRequest(requestId) {
559639
const container = Container.create();
560640
container.messageType = Container.Type.eVersionRequest;
561-
container.versionRequest = { requestId: requestId };
641+
container.versionRequest = { requestId };
562642
const buffer = Container.encode(container).finish();
563643
this.ws.send(buffer);
564644
}

0 commit comments

Comments
 (0)