node-red-contrib-s2 0.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/CHANGELOG.md +16 -0
- package/LICENSE +21 -0
- package/README.md +119 -0
- package/dist/lib/index.d.ts +4 -0
- package/dist/lib/index.js +17 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/s2/messages.d.ts +342 -0
- package/dist/lib/s2/messages.js +330 -0
- package/dist/lib/s2/messages.js.map +1 -0
- package/dist/lib/s2/schedule.d.ts +35 -0
- package/dist/lib/s2/schedule.js +109 -0
- package/dist/lib/s2/schedule.js.map +1 -0
- package/dist/lib/s2/session.d.ts +138 -0
- package/dist/lib/s2/session.js +304 -0
- package/dist/lib/s2/session.js.map +1 -0
- package/dist/lib/transport/websocket.d.ts +58 -0
- package/dist/lib/transport/websocket.js +149 -0
- package/dist/lib/transport/websocket.js.map +1 -0
- package/dist/nodes/s2-cem-config/index.d.ts +3 -0
- package/dist/nodes/s2-cem-config/index.html +54 -0
- package/dist/nodes/s2-cem-config/index.js +16 -0
- package/dist/nodes/s2-cem-config/index.js.map +1 -0
- package/dist/nodes/s2-rm/icons/s2-logo.svg +14 -0
- package/dist/nodes/s2-rm/index.d.ts +34 -0
- package/dist/nodes/s2-rm/index.html +167 -0
- package/dist/nodes/s2-rm/index.js +655 -0
- package/dist/nodes/s2-rm/index.js.map +1 -0
- package/dist/nodes/s2-rm-config/index.d.ts +3 -0
- package/dist/nodes/s2-rm-config/index.html +254 -0
- package/dist/nodes/s2-rm-config/index.js +20 -0
- package/dist/nodes/s2-rm-config/index.js.map +1 -0
- package/dist/nodes/s2-websocket/icons/s2-logo.svg +14 -0
- package/dist/nodes/s2-websocket/index.d.ts +22 -0
- package/dist/nodes/s2-websocket/index.html +83 -0
- package/dist/nodes/s2-websocket/index.js +127 -0
- package/dist/nodes/s2-websocket/index.js.map +1 -0
- package/dist/types/config-nodes.d.ts +39 -0
- package/dist/types/config-nodes.js +3 -0
- package/dist/types/config-nodes.js.map +1 -0
- package/package.json +84 -0
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RevokableObjects = exports.InstructionStatus = exports.ReceptionStatusResult = exports.GRID_CONNECTIONS = exports.ControlType = exports.MessageType = void 0;
|
|
4
|
+
exports.gridConnectionToWatts = gridConnectionToWatts;
|
|
5
|
+
exports.parse = parse;
|
|
6
|
+
exports.serialize = serialize;
|
|
7
|
+
exports.makeReceptionStatus = makeReceptionStatus;
|
|
8
|
+
exports.makeHandshake = makeHandshake;
|
|
9
|
+
exports.makeResourceManagerDetails = makeResourceManagerDetails;
|
|
10
|
+
exports.makeOMBCSystemDescription = makeOMBCSystemDescription;
|
|
11
|
+
exports.makeOMBCStatus = makeOMBCStatus;
|
|
12
|
+
exports.makePowerMeasurement = makePowerMeasurement;
|
|
13
|
+
exports.makePEBCPowerConstraints = makePEBCPowerConstraints;
|
|
14
|
+
exports.makePowerForecast = makePowerForecast;
|
|
15
|
+
exports.makeInstructionStatusUpdate = makeInstructionStatusUpdate;
|
|
16
|
+
exports.generateId = generateId;
|
|
17
|
+
const crypto_1 = require("crypto");
|
|
18
|
+
/**
|
|
19
|
+
* S2 protocol message type constants (EN 50491-12-2).
|
|
20
|
+
* These are the message_type values used in S2 JSON messages.
|
|
21
|
+
*/
|
|
22
|
+
exports.MessageType = Object.freeze({
|
|
23
|
+
// Handshake
|
|
24
|
+
HANDSHAKE: 'Handshake',
|
|
25
|
+
HANDSHAKE_RESPONSE: 'HandshakeResponse',
|
|
26
|
+
// Session
|
|
27
|
+
SESSION_REQUEST: 'SessionRequest',
|
|
28
|
+
// Resource Manager -> CEM
|
|
29
|
+
RESOURCE_MANAGER_DETAILS: 'ResourceManagerDetails',
|
|
30
|
+
POWER_MEASUREMENT: 'PowerMeasurement',
|
|
31
|
+
RECEPTION_STATUS: 'ReceptionStatus',
|
|
32
|
+
REVOKE_OBJECT: 'RevokeObject',
|
|
33
|
+
SELECT_CONTROL_TYPE: 'SelectControlType',
|
|
34
|
+
// CEM -> Resource Manager
|
|
35
|
+
INSTRUCTION: 'Instruction',
|
|
36
|
+
// Fill-rate Based Control (FRBC)
|
|
37
|
+
FRBC_ACTUATOR_STATUS: 'FRBC.ActuatorStatus',
|
|
38
|
+
FRBC_FILL_LEVEL_TARGET_PROFILE: 'FRBC.FillLevelTargetProfile',
|
|
39
|
+
FRBC_LEAKAGE_BEHAVIOUR: 'FRBC.LeakagebBehaviour',
|
|
40
|
+
FRBC_STORAGE_STATUS: 'FRBC.StorageStatus',
|
|
41
|
+
FRBC_SYSTEM_DESCRIPTION: 'FRBC.SystemDescription',
|
|
42
|
+
FRBC_TIMER_STATUS: 'FRBC.TimerStatus',
|
|
43
|
+
FRBC_USAGE_FORECAST: 'FRBC.UsageForecast',
|
|
44
|
+
FRBC_INSTRUCTION: 'FRBC.Instruction',
|
|
45
|
+
// Demand Driven Based Control (DDBC)
|
|
46
|
+
DDBC_ACTUAL_POWER: 'DDBC.ActualPower',
|
|
47
|
+
DDBC_AVERAGE_DEMAND_RATE_FORECAST: 'DDBC.AverageDemandRateForecast',
|
|
48
|
+
DDBC_SYSTEM_DESCRIPTION: 'DDBC.SystemDescription',
|
|
49
|
+
DDBC_TIMER_STATUS: 'DDBC.TimerStatus',
|
|
50
|
+
DDBC_INSTRUCTION: 'DDBC.Instruction',
|
|
51
|
+
// Power Profile Based Control (PPBC)
|
|
52
|
+
PPBC_POWER_PROFILE_STATUS: 'PPBC.PowerProfileStatus',
|
|
53
|
+
PPBC_SCHEDULE_INSTRUCTION: 'PPBC.ScheduleInstruction',
|
|
54
|
+
PPBC_START_INTERRUPTION_INSTRUCTION: 'PPBC.StartInterruptionInstruction',
|
|
55
|
+
PPBC_END_INTERRUPTION_INSTRUCTION: 'PPBC.EndInterruptionInstruction',
|
|
56
|
+
PPBC_POWER_PROFILE: 'PPBC.PowerProfileDefinition',
|
|
57
|
+
// Operation Mode Based Control (OMBC)
|
|
58
|
+
OMBC_SYSTEM_DESCRIPTION: 'OMBC.SystemDescription',
|
|
59
|
+
OMBC_STATUS: 'OMBC.Status',
|
|
60
|
+
OMBC_INSTRUCTION: 'OMBC.Instruction',
|
|
61
|
+
// Power Envelope Based Control (PEBC)
|
|
62
|
+
PEBC_POWER_CONSTRAINTS: 'PEBC.PowerConstraints',
|
|
63
|
+
PEBC_DEVICE_CONSTRAINTS: 'PEBC.DeviceConstraints',
|
|
64
|
+
PEBC_ENERGY_CONSTRAINT: 'PEBC.EnergyConstraint',
|
|
65
|
+
PEBC_INSTRUCTION: 'PEBC.Instruction',
|
|
66
|
+
// Common
|
|
67
|
+
POWER_FORECAST: 'PowerForecast',
|
|
68
|
+
INSTRUCTION_STATUS_UPDATE: 'InstructionStatusUpdate'
|
|
69
|
+
});
|
|
70
|
+
/**
|
|
71
|
+
* S2 control type identifiers (full names as used in s2python / s2-ws-json).
|
|
72
|
+
*/
|
|
73
|
+
exports.ControlType = Object.freeze({
|
|
74
|
+
NOT_CONTROLABLE: 'NOT_CONTROLABLE',
|
|
75
|
+
OMBC: 'OPERATION_MODE_BASED_CONTROL',
|
|
76
|
+
FRBC: 'FILL_RATE_BASED_CONTROL',
|
|
77
|
+
DDBC: 'DEMAND_DRIVEN_BASED_CONTROL',
|
|
78
|
+
PPBC: 'POWER_PROFILE_BASED_CONTROL',
|
|
79
|
+
PEBC: 'POWER_ENVELOPE_BASED_CONTROL',
|
|
80
|
+
NO_SELECTION: 'NO_SELECTION'
|
|
81
|
+
});
|
|
82
|
+
/**
|
|
83
|
+
* ReceptionStatus result values (matches s2python ReceptionStatusValues).
|
|
84
|
+
*/
|
|
85
|
+
/**
|
|
86
|
+
* Standard European grid connection types with their max power capacity at 230V nominal.
|
|
87
|
+
* Used to set PEBC power constraint outer limits (bidirectional: [-maxWatts, +maxWatts]).
|
|
88
|
+
*/
|
|
89
|
+
exports.GRID_CONNECTIONS = Object.freeze({
|
|
90
|
+
'1x16A': { phases: 1, ampsPerPhase: 16, maxWatts: 3680 },
|
|
91
|
+
'3x16A': { phases: 3, ampsPerPhase: 16, maxWatts: 11040 },
|
|
92
|
+
'3x25A': { phases: 3, ampsPerPhase: 25, maxWatts: 17250 },
|
|
93
|
+
'3x32A': { phases: 3, ampsPerPhase: 32, maxWatts: 22080 },
|
|
94
|
+
'3x40A': { phases: 3, ampsPerPhase: 40, maxWatts: 27600 },
|
|
95
|
+
'3x63A': { phases: 3, ampsPerPhase: 63, maxWatts: 43470 }
|
|
96
|
+
});
|
|
97
|
+
/**
|
|
98
|
+
* Returns the max power in watts for a given grid connection.
|
|
99
|
+
* For 'custom', returns customMaxPowerW if provided.
|
|
100
|
+
* Returns null if the connection is unknown or unset.
|
|
101
|
+
*/
|
|
102
|
+
function gridConnectionToWatts(gridConnection, customMaxPowerW) {
|
|
103
|
+
if (!gridConnection)
|
|
104
|
+
return null;
|
|
105
|
+
if (gridConnection === 'custom')
|
|
106
|
+
return customMaxPowerW !== null && customMaxPowerW !== void 0 ? customMaxPowerW : null;
|
|
107
|
+
const conn = exports.GRID_CONNECTIONS[gridConnection];
|
|
108
|
+
return conn ? conn.maxWatts : null;
|
|
109
|
+
}
|
|
110
|
+
exports.ReceptionStatusResult = Object.freeze({
|
|
111
|
+
OK: 'OK',
|
|
112
|
+
INVALID_DATA: 'INVALID_DATA',
|
|
113
|
+
INVALID_MESSAGE: 'INVALID_MESSAGE',
|
|
114
|
+
INVALID_CONTENT: 'INVALID_CONTENT',
|
|
115
|
+
TEMPORARY_ERROR: 'TEMPORARY_ERROR',
|
|
116
|
+
PERMANENT_ERROR: 'PERMANENT_ERROR'
|
|
117
|
+
});
|
|
118
|
+
exports.InstructionStatus = Object.freeze({
|
|
119
|
+
NEW: 'NEW',
|
|
120
|
+
ACCEPTED: 'ACCEPTED',
|
|
121
|
+
REJECTED: 'REJECTED',
|
|
122
|
+
REVOKED: 'REVOKED',
|
|
123
|
+
STARTED: 'STARTED',
|
|
124
|
+
SUCCEEDED: 'SUCCEEDED',
|
|
125
|
+
ABORTED: 'ABORTED'
|
|
126
|
+
});
|
|
127
|
+
exports.RevokableObjects = Object.freeze({
|
|
128
|
+
DDBC_AVERAGE_DEMAND_RATE_FORECAST: 'DDBC.AverageDemandRateForecast',
|
|
129
|
+
DDBC_INSTRUCTION: 'DDBC.Instruction',
|
|
130
|
+
DDBC_SYSTEM_DESCRIPTION: 'DDBC.SystemDescription',
|
|
131
|
+
FRBC_FILL_LEVEL_TARGET_PROFILE: 'FRBC.FillLevelTargetProfile',
|
|
132
|
+
FRBC_INSTRUCTION: 'FRBC.Instruction',
|
|
133
|
+
FRBC_LEAKAGE_BEHAVIOUR: 'FRBC.LeakageBehaviour',
|
|
134
|
+
FRBC_SYSTEM_DESCRIPTION: 'FRBC.SystemDescription',
|
|
135
|
+
FRBC_USAGE_FORECAST: 'FRBC.UsageForecast',
|
|
136
|
+
OMBC_INSTRUCTION: 'OMBC.Instruction',
|
|
137
|
+
OMBC_SYSTEM_DESCRIPTION: 'OMBC.SystemDescription',
|
|
138
|
+
PEBC_ENERGY_CONSTRAINT: 'PEBC.EnergyConstraint',
|
|
139
|
+
PEBC_INSTRUCTION: 'PEBC.Instruction',
|
|
140
|
+
PEBC_POWER_CONSTRAINTS: 'PEBC.PowerConstraints',
|
|
141
|
+
PPBC_END_INTERRUPTION_INSTRUCTION: 'PPBC.EndInterruptionInstruction',
|
|
142
|
+
PPBC_POWER_PROFILE_DEFINITION: 'PPBC.PowerProfileDefinition',
|
|
143
|
+
PPBC_SCHEDULE_INSTRUCTION: 'PPBC.ScheduleInstruction',
|
|
144
|
+
PPBC_START_INTERRUPTION_INSTRUCTION: 'PPBC.StartInterruptionInstruction'
|
|
145
|
+
});
|
|
146
|
+
/**
|
|
147
|
+
* Parse a raw WebSocket message string into an S2 message object.
|
|
148
|
+
* Returns null and calls onError if parsing fails.
|
|
149
|
+
*
|
|
150
|
+
* @param raw - raw JSON string
|
|
151
|
+
* @param onError - called with an Error if parsing fails
|
|
152
|
+
*/
|
|
153
|
+
function parse(raw, onError) {
|
|
154
|
+
try {
|
|
155
|
+
const msg = JSON.parse(raw);
|
|
156
|
+
if (!msg.message_type) {
|
|
157
|
+
onError(new Error('S2 message missing message_type'));
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
return msg;
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
onError(new Error(`Failed to parse S2 message: ${err.message}`));
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Serialize an S2 message object to a string for sending over the wire.
|
|
169
|
+
*/
|
|
170
|
+
function serialize(msg) {
|
|
171
|
+
return JSON.stringify(msg);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Create a ReceptionStatus message acknowledging a received message.
|
|
175
|
+
*
|
|
176
|
+
* @param subjectMessageId - message_id of the message being acknowledged
|
|
177
|
+
* @param status - one of ReceptionStatusResult values
|
|
178
|
+
* @param diagnosticLabel - optional human-readable diagnostic
|
|
179
|
+
*/
|
|
180
|
+
function makeReceptionStatus(subjectMessageId, status, diagnosticLabel) {
|
|
181
|
+
const msg = {
|
|
182
|
+
message_type: exports.MessageType.RECEPTION_STATUS,
|
|
183
|
+
subject_message_id: subjectMessageId,
|
|
184
|
+
status
|
|
185
|
+
};
|
|
186
|
+
if (diagnosticLabel) {
|
|
187
|
+
msg.diagnostic_label = diagnosticLabel;
|
|
188
|
+
}
|
|
189
|
+
return msg;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Create a Handshake message (sent by RM on connect).
|
|
193
|
+
*
|
|
194
|
+
* @param rmId - unique ID identifying this Resource Manager
|
|
195
|
+
*/
|
|
196
|
+
function makeHandshake(rmId) {
|
|
197
|
+
void rmId; // included in API for symmetry; not sent in Handshake per spec
|
|
198
|
+
return {
|
|
199
|
+
message_type: exports.MessageType.HANDSHAKE,
|
|
200
|
+
message_id: generateId(),
|
|
201
|
+
role: 'RM',
|
|
202
|
+
supported_protocol_versions: ['0.0.2-beta']
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Create a ResourceManagerDetails message (sent by RM after HandshakeResponse).
|
|
207
|
+
*/
|
|
208
|
+
function makeResourceManagerDetails(details) {
|
|
209
|
+
return {
|
|
210
|
+
message_type: exports.MessageType.RESOURCE_MANAGER_DETAILS,
|
|
211
|
+
message_id: generateId(),
|
|
212
|
+
resource_id: details.resourceId,
|
|
213
|
+
name: details.name,
|
|
214
|
+
roles: details.roles,
|
|
215
|
+
manufacturer: details.manufacturer || '',
|
|
216
|
+
model: details.model || '',
|
|
217
|
+
serial_number: details.serialNumber || '',
|
|
218
|
+
firmware_version: details.firmwareVersion || '',
|
|
219
|
+
available_control_types: details.availableControlTypes,
|
|
220
|
+
provides_forecast: details.providesForecast || false,
|
|
221
|
+
provides_power_measurement_types: details.providesPowerMeasurementTypes || [],
|
|
222
|
+
instruction_processing_delay: details.instructionProcessingDelay || 0
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Create an OMBC.SystemDescription message.
|
|
227
|
+
*/
|
|
228
|
+
function makeOMBCSystemDescription(config) {
|
|
229
|
+
return {
|
|
230
|
+
message_type: exports.MessageType.OMBC_SYSTEM_DESCRIPTION,
|
|
231
|
+
message_id: generateId(),
|
|
232
|
+
valid_from: new Date().toISOString(),
|
|
233
|
+
operation_modes: config.operationModes || [],
|
|
234
|
+
transitions: config.transitions || [],
|
|
235
|
+
timers: config.timers || []
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Create an OMBC.Status message.
|
|
240
|
+
*/
|
|
241
|
+
function makeOMBCStatus(status) {
|
|
242
|
+
const msg = {
|
|
243
|
+
message_type: exports.MessageType.OMBC_STATUS,
|
|
244
|
+
message_id: generateId(),
|
|
245
|
+
active_operation_mode_id: status.activeOperationModeId,
|
|
246
|
+
operation_mode_factor: status.operationModeFactor !== undefined ? status.operationModeFactor : 1
|
|
247
|
+
};
|
|
248
|
+
if (status.previousOperationModeId) {
|
|
249
|
+
msg.previous_operation_mode_id = status.previousOperationModeId;
|
|
250
|
+
}
|
|
251
|
+
if (status.transitionTimestamp) {
|
|
252
|
+
msg.transition_timestamp = status.transitionTimestamp;
|
|
253
|
+
}
|
|
254
|
+
return msg;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Create a PowerMeasurement message (sent by RM to report current power).
|
|
258
|
+
*
|
|
259
|
+
* @param values - array of { commodity_quantity, value } objects
|
|
260
|
+
*/
|
|
261
|
+
function makePowerMeasurement(values) {
|
|
262
|
+
return {
|
|
263
|
+
message_type: exports.MessageType.POWER_MEASUREMENT,
|
|
264
|
+
message_id: generateId(),
|
|
265
|
+
measurement_timestamp: new Date().toISOString(),
|
|
266
|
+
values
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Build a PEBC.PowerConstraints message with matching LOWER_LIMIT and
|
|
271
|
+
* UPPER_LIMIT ranges and consequence_type DEFER.
|
|
272
|
+
*
|
|
273
|
+
* Wire format (s2-ws-json 0.0.2-beta):
|
|
274
|
+
* id + allowed_limit_ranges are top-level fields on the message itself,
|
|
275
|
+
* not nested under a power_constraints array.
|
|
276
|
+
*/
|
|
277
|
+
function makePEBCPowerConstraints(input) {
|
|
278
|
+
var _a;
|
|
279
|
+
const validFrom = (_a = input.validFrom) !== null && _a !== void 0 ? _a : new Date().toISOString();
|
|
280
|
+
const rangeBoundary = { start_of_range: input.minPower, end_of_range: input.maxPower };
|
|
281
|
+
return {
|
|
282
|
+
message_type: exports.MessageType.PEBC_POWER_CONSTRAINTS,
|
|
283
|
+
message_id: generateId(),
|
|
284
|
+
id: generateId(),
|
|
285
|
+
valid_from: validFrom,
|
|
286
|
+
valid_until: null,
|
|
287
|
+
consequence_type: 'DEFER',
|
|
288
|
+
allowed_limit_ranges: [
|
|
289
|
+
{ commodity_quantity: input.commodityQuantity, limit_type: 'LOWER_LIMIT', range_boundary: rangeBoundary, abnormal_condition_only: false },
|
|
290
|
+
{ commodity_quantity: input.commodityQuantity, limit_type: 'UPPER_LIMIT', range_boundary: rangeBoundary, abnormal_condition_only: false }
|
|
291
|
+
]
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Build a PowerForecast message from pre-formed elements.
|
|
296
|
+
*
|
|
297
|
+
* @param input.startTime - ISO 8601 timezone-aware datetime for the first element
|
|
298
|
+
* @param input.elements - array of { duration (ms), power_values: [{ commodity_quantity, value_expected }] }
|
|
299
|
+
*/
|
|
300
|
+
function makePowerForecast(input) {
|
|
301
|
+
return {
|
|
302
|
+
message_type: exports.MessageType.POWER_FORECAST,
|
|
303
|
+
message_id: generateId(),
|
|
304
|
+
start_time: input.startTime,
|
|
305
|
+
elements: input.elements
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Create an InstructionStatusUpdate message reporting the current lifecycle state of an instruction.
|
|
310
|
+
*
|
|
311
|
+
* @param instructionId - the `id` field of the instruction (not its message_id)
|
|
312
|
+
* @param status - one of InstructionStatus values
|
|
313
|
+
*/
|
|
314
|
+
function makeInstructionStatusUpdate(instructionId, status) {
|
|
315
|
+
return {
|
|
316
|
+
message_type: exports.MessageType.INSTRUCTION_STATUS_UPDATE,
|
|
317
|
+
message_id: generateId(),
|
|
318
|
+
instruction_id: instructionId,
|
|
319
|
+
status_type: status,
|
|
320
|
+
timestamp: new Date().toISOString()
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Generate a UUID v4 message ID.
|
|
325
|
+
* Node >=14.17.4 is required, which includes crypto.randomUUID.
|
|
326
|
+
*/
|
|
327
|
+
function generateId() {
|
|
328
|
+
return (0, crypto_1.randomUUID)();
|
|
329
|
+
}
|
|
330
|
+
//# sourceMappingURL=messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../../src/lib/s2/messages.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { PowerForecastInput } from './messages';
|
|
2
|
+
export interface ScheduleElement {
|
|
3
|
+
startMs: number;
|
|
4
|
+
endMs: number;
|
|
5
|
+
duration: number;
|
|
6
|
+
lowerBound: number | null;
|
|
7
|
+
upperBound: number | null;
|
|
8
|
+
}
|
|
9
|
+
export interface PebcSchedule {
|
|
10
|
+
receivedAt: number;
|
|
11
|
+
cemId: string;
|
|
12
|
+
instructionId: string;
|
|
13
|
+
commodityQuantity: string;
|
|
14
|
+
elements: ScheduleElement[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Parse a PEBC.Instruction message into a PebcSchedule with absolute timestamps.
|
|
18
|
+
* Returns null if the message contains no usable power_envelopes.
|
|
19
|
+
*/
|
|
20
|
+
export declare function parsePebcInstruction(msg: Record<string, unknown>, receivedAt: number, cemId?: string): PebcSchedule | null;
|
|
21
|
+
/**
|
|
22
|
+
* Return the element active at nowMs, or null if outside the schedule window.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getActiveElement(schedule: PebcSchedule, nowMs: number): ScheduleElement | null;
|
|
25
|
+
/**
|
|
26
|
+
* Return the start time (ms) of the element that follows the currently active one,
|
|
27
|
+
* or null if in the last element or outside the schedule window.
|
|
28
|
+
*/
|
|
29
|
+
export declare function getNextElementStart(schedule: PebcSchedule, nowMs: number): number | null;
|
|
30
|
+
/**
|
|
31
|
+
* Return a copy of forecast with value_expected (and value_upper/lower_limit when present)
|
|
32
|
+
* clamped to the tightest PEBC bounds overlapping each forecast element's time window.
|
|
33
|
+
* Elements with no overlapping PEBC bound are passed through unchanged.
|
|
34
|
+
*/
|
|
35
|
+
export declare function capForecastToSchedule(forecast: PowerForecastInput, schedule: PebcSchedule): PowerForecastInput;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parsePebcInstruction = parsePebcInstruction;
|
|
4
|
+
exports.getActiveElement = getActiveElement;
|
|
5
|
+
exports.getNextElementStart = getNextElementStart;
|
|
6
|
+
exports.capForecastToSchedule = capForecastToSchedule;
|
|
7
|
+
/**
|
|
8
|
+
* Parse a PEBC.Instruction message into a PebcSchedule with absolute timestamps.
|
|
9
|
+
* Returns null if the message contains no usable power_envelopes.
|
|
10
|
+
*/
|
|
11
|
+
function parsePebcInstruction(msg, receivedAt, cemId = '') {
|
|
12
|
+
var _a;
|
|
13
|
+
const envelopes = msg.power_envelopes;
|
|
14
|
+
if (!Array.isArray(envelopes) || envelopes.length === 0)
|
|
15
|
+
return null;
|
|
16
|
+
const envelope = envelopes[0];
|
|
17
|
+
const rawElements = (_a = envelope.power_envelope_elements) !== null && _a !== void 0 ? _a : [];
|
|
18
|
+
const executionTimeMs = msg.execution_time
|
|
19
|
+
? new Date(msg.execution_time).getTime()
|
|
20
|
+
: receivedAt;
|
|
21
|
+
let cursor = executionTimeMs;
|
|
22
|
+
const elements = rawElements.map((el) => {
|
|
23
|
+
var _a, _b;
|
|
24
|
+
const startMs = cursor;
|
|
25
|
+
const endMs = cursor + el.duration;
|
|
26
|
+
cursor = endMs;
|
|
27
|
+
return {
|
|
28
|
+
startMs,
|
|
29
|
+
endMs,
|
|
30
|
+
duration: el.duration,
|
|
31
|
+
lowerBound: (_a = el.lower_limit) !== null && _a !== void 0 ? _a : null,
|
|
32
|
+
upperBound: (_b = el.upper_limit) !== null && _b !== void 0 ? _b : null
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
return {
|
|
36
|
+
receivedAt,
|
|
37
|
+
cemId,
|
|
38
|
+
instructionId: msg.id,
|
|
39
|
+
commodityQuantity: envelope.commodity_quantity,
|
|
40
|
+
elements
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Return the element active at nowMs, or null if outside the schedule window.
|
|
45
|
+
*/
|
|
46
|
+
function getActiveElement(schedule, nowMs) {
|
|
47
|
+
for (const el of schedule.elements) {
|
|
48
|
+
if (nowMs >= el.startMs && nowMs < el.endMs)
|
|
49
|
+
return el;
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Return the start time (ms) of the element that follows the currently active one,
|
|
55
|
+
* or null if in the last element or outside the schedule window.
|
|
56
|
+
*/
|
|
57
|
+
function getNextElementStart(schedule, nowMs) {
|
|
58
|
+
for (let i = 0; i < schedule.elements.length - 1; i++) {
|
|
59
|
+
const el = schedule.elements[i];
|
|
60
|
+
if (nowMs >= el.startMs && nowMs < el.endMs)
|
|
61
|
+
return schedule.elements[i + 1].startMs;
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Return a copy of forecast with value_expected (and value_upper/lower_limit when present)
|
|
67
|
+
* clamped to the tightest PEBC bounds overlapping each forecast element's time window.
|
|
68
|
+
* Elements with no overlapping PEBC bound are passed through unchanged.
|
|
69
|
+
*/
|
|
70
|
+
function capForecastToSchedule(forecast, schedule) {
|
|
71
|
+
let cursor = new Date(forecast.startTime).getTime();
|
|
72
|
+
const elements = forecast.elements.map(el => {
|
|
73
|
+
const elStart = cursor;
|
|
74
|
+
const elEnd = cursor + el.duration;
|
|
75
|
+
cursor = elEnd;
|
|
76
|
+
let effectiveUpper = null;
|
|
77
|
+
let effectiveLower = null;
|
|
78
|
+
for (const schedEl of schedule.elements) {
|
|
79
|
+
if (elEnd <= schedEl.startMs || elStart >= schedEl.endMs)
|
|
80
|
+
continue;
|
|
81
|
+
if (schedEl.upperBound !== null) {
|
|
82
|
+
effectiveUpper = effectiveUpper === null ? schedEl.upperBound : Math.min(effectiveUpper, schedEl.upperBound);
|
|
83
|
+
}
|
|
84
|
+
if (schedEl.lowerBound !== null) {
|
|
85
|
+
effectiveLower = effectiveLower === null ? schedEl.lowerBound : Math.max(effectiveLower, schedEl.lowerBound);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (effectiveUpper === null && effectiveLower === null)
|
|
89
|
+
return el;
|
|
90
|
+
const power_values = el.power_values.map(pv => {
|
|
91
|
+
let expected = pv.value_expected;
|
|
92
|
+
if (effectiveUpper !== null)
|
|
93
|
+
expected = Math.min(expected, effectiveUpper);
|
|
94
|
+
if (effectiveLower !== null)
|
|
95
|
+
expected = Math.max(expected, effectiveLower);
|
|
96
|
+
const capped = { ...pv, value_expected: expected };
|
|
97
|
+
if (pv.value_upper_limit !== undefined && effectiveUpper !== null) {
|
|
98
|
+
capped.value_upper_limit = Math.min(pv.value_upper_limit, effectiveUpper);
|
|
99
|
+
}
|
|
100
|
+
if (pv.value_lower_limit !== undefined && effectiveLower !== null) {
|
|
101
|
+
capped.value_lower_limit = Math.max(pv.value_lower_limit, effectiveLower);
|
|
102
|
+
}
|
|
103
|
+
return capped;
|
|
104
|
+
});
|
|
105
|
+
return { ...el, power_values };
|
|
106
|
+
});
|
|
107
|
+
return { ...forecast, elements };
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=schedule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schedule.js","sourceRoot":"","sources":["../../../src/lib/s2/schedule.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { ControlTypeValue, InstructionStatusValue, S2IncomingMessage, RmDetails, OMBCSystemDescriptionConfig, OMBCStatusConfig, PEBCPowerConstraintsInput } from './messages';
|
|
2
|
+
/**
|
|
3
|
+
* S2 session states.
|
|
4
|
+
*/
|
|
5
|
+
export declare const State: Readonly<{
|
|
6
|
+
readonly HANDSHAKING: "HANDSHAKING";
|
|
7
|
+
readonly CONNECTED: "CONNECTED";
|
|
8
|
+
}>;
|
|
9
|
+
export type StateValue = (typeof State)[keyof typeof State];
|
|
10
|
+
export interface OMBCConfig {
|
|
11
|
+
systemDescription?: OMBCSystemDescriptionConfig;
|
|
12
|
+
status?: OMBCStatusConfig;
|
|
13
|
+
}
|
|
14
|
+
export interface ControlTypeConfig {
|
|
15
|
+
OMBC?: OMBCConfig;
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
}
|
|
18
|
+
export interface S2SessionOptions {
|
|
19
|
+
cemId: string;
|
|
20
|
+
rmDetails?: RmDetails;
|
|
21
|
+
controlTypeConfig?: ControlTypeConfig;
|
|
22
|
+
onSend?: (msg: object) => void;
|
|
23
|
+
onStateChange?: (state: StateValue) => void;
|
|
24
|
+
onMessage?: (msg: S2IncomingMessage) => void;
|
|
25
|
+
onInstruction?: (msg: S2IncomingMessage) => void;
|
|
26
|
+
onError?: (err: Error) => void;
|
|
27
|
+
retryDelayMs?: number;
|
|
28
|
+
/** When true, skip auto-sending InstructionStatusUpdate(ACCEPTED) on instruction receipt.
|
|
29
|
+
* ReceptionStatus and OMBC.Status are still sent. Use to reduce D-Bus traffic when
|
|
30
|
+
* the CEM does not require acknowledgment messages. */
|
|
31
|
+
skipInstructionStatus?: boolean;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* S2Session manages the S2 protocol state for a single CEM connection.
|
|
35
|
+
*
|
|
36
|
+
* The RM (us) initiates the Handshake immediately after the CEM connects.
|
|
37
|
+
* This applies to both transports:
|
|
38
|
+
* - D-Bus (acload): CEM calls Connect on D-Bus, RM sends Handshake via Message signal
|
|
39
|
+
* - WebSocket (future): CEM opens WS connection, RM sends Handshake over the socket
|
|
40
|
+
*
|
|
41
|
+
* Usage:
|
|
42
|
+
* const session = new S2Session({
|
|
43
|
+
* cemId,
|
|
44
|
+
* rmDetails,
|
|
45
|
+
* controlTypeConfig: { // optional control type configuration
|
|
46
|
+
* OMBC: {
|
|
47
|
+
* systemDescription: { operationModes: [...], transitions: [], timers: [] },
|
|
48
|
+
* status: { activeOperationModeId: 'mode-1', operationModeFactor: 1 }
|
|
49
|
+
* }
|
|
50
|
+
* },
|
|
51
|
+
* onSend: (msg) => <send S2 message object to CEM>,
|
|
52
|
+
* onStateChange: (state) => ...,
|
|
53
|
+
* onMessage: (msg) => <forward received message downstream>,
|
|
54
|
+
* onError: (err) => ...
|
|
55
|
+
* })
|
|
56
|
+
*
|
|
57
|
+
* session.start() // sends Handshake, call after Connect
|
|
58
|
+
* session.handleMessage(msg) // call for each Message from the CEM
|
|
59
|
+
* session.send(msg) // send an outbound S2 message (only when CONNECTED)
|
|
60
|
+
*/
|
|
61
|
+
export declare class S2Session {
|
|
62
|
+
private readonly _cemId;
|
|
63
|
+
private readonly _rmDetails;
|
|
64
|
+
private readonly _controlTypeConfig;
|
|
65
|
+
private readonly _onSend;
|
|
66
|
+
private readonly _onStateChange;
|
|
67
|
+
private readonly _onMessage;
|
|
68
|
+
private readonly _onInstruction;
|
|
69
|
+
private readonly _onError;
|
|
70
|
+
private readonly _retryDelayMs;
|
|
71
|
+
private readonly _skipInstructionStatus;
|
|
72
|
+
private readonly _sentMessages;
|
|
73
|
+
private readonly _retryTimers;
|
|
74
|
+
private _state;
|
|
75
|
+
private _selectedControlType;
|
|
76
|
+
private _lastKeepAlive;
|
|
77
|
+
private _pebcPowerConstraints;
|
|
78
|
+
private _currentOMBCStatus;
|
|
79
|
+
constructor({ cemId, rmDetails, controlTypeConfig, onSend, onStateChange, onMessage, onInstruction, onError, retryDelayMs, skipInstructionStatus }: S2SessionOptions);
|
|
80
|
+
get cemId(): string;
|
|
81
|
+
get state(): StateValue;
|
|
82
|
+
get selectedControlType(): ControlTypeValue | string;
|
|
83
|
+
get lastKeepAlive(): Date | null;
|
|
84
|
+
get currentOMBCStatus(): OMBCStatusConfig | null;
|
|
85
|
+
/**
|
|
86
|
+
* Cancel pending retry timers and clear the sent-message buffer.
|
|
87
|
+
* Call when the session is no longer needed (disconnect, node close).
|
|
88
|
+
*/
|
|
89
|
+
dispose(): void;
|
|
90
|
+
/**
|
|
91
|
+
* Record that a keepalive was received from the CEM.
|
|
92
|
+
*/
|
|
93
|
+
keepAlive(): void;
|
|
94
|
+
/**
|
|
95
|
+
* Send the initial Handshake to the CEM. Call once after the CEM connects.
|
|
96
|
+
*/
|
|
97
|
+
start(): void;
|
|
98
|
+
/**
|
|
99
|
+
* Process an S2 message received from the CEM.
|
|
100
|
+
* Accepts a raw JSON string or an already-parsed object.
|
|
101
|
+
*/
|
|
102
|
+
handleMessage(raw: string | S2IncomingMessage): void;
|
|
103
|
+
/**
|
|
104
|
+
* Send an S2 message object to the CEM. Only valid when CONNECTED.
|
|
105
|
+
*/
|
|
106
|
+
send(msg: object): void;
|
|
107
|
+
/**
|
|
108
|
+
* Store PEBC power constraints and send them to the CEM immediately if
|
|
109
|
+
* PEBC is the active control type. Stored constraints are also sent
|
|
110
|
+
* automatically when SelectControlType(PEBC) is received.
|
|
111
|
+
*/
|
|
112
|
+
setPEBCPowerConstraints(input: PEBCPowerConstraintsInput): void;
|
|
113
|
+
/**
|
|
114
|
+
* Update the tracked OMBC status and send OMBC.Status to the CEM.
|
|
115
|
+
* Call after an OMBC.Instruction is dispatched to inform the CEM of the new
|
|
116
|
+
* active operation mode. Also updates the status used when SELECT_CONTROL_TYPE
|
|
117
|
+
* is received again (e.g. after a CEM reconnect).
|
|
118
|
+
*/
|
|
119
|
+
updateOMBCStatus(status: OMBCStatusConfig): void;
|
|
120
|
+
/**
|
|
121
|
+
* Send an InstructionStatusUpdate for an instruction previously received from the CEM.
|
|
122
|
+
* Use this to report STARTED, SUCCEEDED, ABORTED, etc. after ACCEPTED was auto-sent.
|
|
123
|
+
*
|
|
124
|
+
* @param instructionId - the `id` field of the instruction (not its message_id)
|
|
125
|
+
* @param status - one of InstructionStatus values
|
|
126
|
+
*/
|
|
127
|
+
sendInstructionStatus(instructionId: string, status: InstructionStatusValue): void;
|
|
128
|
+
/**
|
|
129
|
+
* Buffer the message by its message_id (if present) and forward to onSend.
|
|
130
|
+
* Buffered messages can be retried when the CEM responds with TEMPORARY_ERROR.
|
|
131
|
+
*/
|
|
132
|
+
private _send;
|
|
133
|
+
private _setState;
|
|
134
|
+
private _handleHandshakeResponse;
|
|
135
|
+
private _handleSelectControlType;
|
|
136
|
+
private _sendOMBCSystemDescriptionAndStatus;
|
|
137
|
+
private _ackAndForward;
|
|
138
|
+
}
|