node-red-contrib-s2 0.1.3 → 0.2.0
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/README.md +36 -8
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/s2/schedule.d.ts +3 -2
- package/dist/lib/s2/schedule.js +8 -7
- package/dist/lib/s2/schedule.js.map +1 -1
- package/dist/lib/s2/session.d.ts +17 -22
- package/dist/lib/s2/session.js +29 -59
- package/dist/lib/s2/session.js.map +1 -1
- package/dist/nodes/s2-cem-config/index.html +10 -0
- package/dist/nodes/s2-ombc/icons/s2-logo.svg +14 -0
- package/dist/nodes/s2-ombc/index.d.ts +30 -0
- package/dist/nodes/s2-ombc/index.html +82 -0
- package/dist/nodes/s2-ombc/index.js +153 -0
- package/dist/nodes/s2-ombc/index.js.map +1 -0
- package/dist/nodes/s2-ombc-config/index.d.ts +3 -0
- package/dist/nodes/s2-ombc-config/index.html +428 -0
- package/dist/nodes/s2-ombc-config/index.js +9 -0
- package/dist/nodes/s2-ombc-config/index.js.map +1 -0
- package/dist/nodes/s2-pebc/icons/s2-logo.svg +14 -0
- package/dist/nodes/s2-pebc/index.d.ts +44 -0
- package/dist/nodes/s2-pebc/index.html +85 -0
- package/dist/nodes/s2-pebc/index.js +417 -0
- package/dist/nodes/s2-pebc/index.js.map +1 -0
- package/dist/nodes/s2-pebc-config/index.d.ts +3 -0
- package/dist/nodes/s2-pebc-config/index.html +64 -0
- package/dist/nodes/s2-pebc-config/index.js +10 -0
- package/dist/nodes/s2-pebc-config/index.js.map +1 -0
- package/dist/nodes/s2-rm/index.d.ts +21 -11
- package/dist/nodes/s2-rm/index.html +12 -88
- package/dist/nodes/s2-rm/index.js +85 -309
- package/dist/nodes/s2-rm/index.js.map +1 -1
- package/dist/nodes/s2-rm-config/index.html +34 -66
- package/dist/nodes/s2-rm-config/index.js +2 -2
- package/dist/nodes/s2-rm-config/index.js.map +1 -1
- package/dist/types/config-nodes.d.ts +20 -6
- package/package.json +6 -2
- package/resources/s2-styles.css +101 -2
package/README.md
CHANGED
|
@@ -13,22 +13,28 @@ S2 is a European standard for demand-side energy flexibility. It defines how a C
|
|
|
13
13
|
|
|
14
14
|
| Node | Description |
|
|
15
15
|
|------|-------------|
|
|
16
|
-
| **s2-rm** | S2 Resource Manager -
|
|
17
|
-
| **s2-rm-config** | Configuration for RM identity: resource ID, name, roles, control types, serial number |
|
|
16
|
+
| **s2-rm** | S2 Resource Manager - generic S2 protocol state machine (handshake, control-type selection, instruction ack/routing) for one or more CEMs, independent of any specific control type |
|
|
17
|
+
| **s2-rm-config** | Configuration for RM identity: resource ID, name, roles, control types, serial number, power measurement/forecast |
|
|
18
|
+
| **s2-ombc** | Operation Mode Based Control - declares the OMBC system description, resolves OMBC instructions, and confirms operation mode changes back to the CEM |
|
|
19
|
+
| **s2-ombc-config** | Configuration for `s2-ombc`: OMBC system description (operation modes, transitions, timers), with a friendly editor for the common case and a raw-JSON Advanced mode for everything else |
|
|
20
|
+
| **s2-pebc** | Power Envelope Based Control - accumulates power envelope schedules from PEBC instructions, dispatches the active bound as it becomes effective, caps outgoing PowerForecasts to the accumulated schedule, and (optionally) resolves which side of an asymmetric bound currently applies from your PowerMeasurement |
|
|
21
|
+
| **s2-pebc-config** | Configuration for `s2-pebc`: default power constraints (grid connection preset or custom wattage) |
|
|
18
22
|
| **s2-cem-config** | Configuration for CEM connection (WebSocket URL and credentials) |
|
|
19
23
|
| **s2-websocket** | WebSocket transport for S2 communication with a CEM |
|
|
20
24
|
|
|
21
25
|
## Features
|
|
22
26
|
|
|
23
27
|
- S2 protocol handshake and session management
|
|
24
|
-
- Operation Mode Based Control (OMBC)
|
|
25
|
-
- Power Envelope Based Control (PEBC) with configurable power constraints
|
|
28
|
+
- Operation Mode Based Control (OMBC), via the dedicated **s2-ombc** node
|
|
29
|
+
- Power Envelope Based Control (PEBC) with configurable power constraints, via the dedicated **s2-pebc** node
|
|
26
30
|
- PowerMeasurement forwarding (3-phase symmetric or per-phase L1/L2/L3)
|
|
27
31
|
- PowerForecast support
|
|
28
32
|
- Multiple concurrent CEM sessions
|
|
29
33
|
- Configurable RM roles (Consumer, Producer, Storage)
|
|
30
34
|
- Context variable templates in serial number (e.g. `{{global.vrmId}}`)
|
|
31
35
|
|
|
36
|
+
Other S2 control types (FRBC, DDBC, PPBC) have no dedicated node yet - **s2-rm** forwards their instructions on its instructions output, enriched with `msg.controlType`, for you to handle in your own flow.
|
|
37
|
+
|
|
32
38
|
## Installation
|
|
33
39
|
|
|
34
40
|
Install via the Node-RED palette manager, or from the command line:
|
|
@@ -45,8 +51,18 @@ npm install node-red-contrib-s2
|
|
|
45
51
|
3. Wire an **s2-websocket** node to an **s2-rm** node:
|
|
46
52
|
- s2-websocket output 2 -> s2-rm input
|
|
47
53
|
- s2-rm output 1 -> s2-websocket input
|
|
48
|
-
4. s2-rm output 2 carries S2 messages from the CEM (e.g. SelectControlType, ReceptionStatus).
|
|
49
|
-
5. s2-rm output 3 carries instructions from the CEM (e.g.
|
|
54
|
+
4. s2-rm output 2 carries S2 messages from the CEM (e.g. SelectControlType, ReceptionStatus, RevokeObject).
|
|
55
|
+
5. s2-rm output 3 carries instructions from the CEM, enriched with `msg.controlType` and namespaced under a matching key (e.g. `msg.ombc`, `msg.pebc`).
|
|
56
|
+
6. For OMBC or PEBC, add the matching control-type node (**s2-ombc** + **s2-ombc-config**, or **s2-pebc** + **s2-pebc-config**) and wire it up:
|
|
57
|
+
- s2-rm output 2 -> control-type node input (so it can observe `SelectControlType`/`RevokeObject`)
|
|
58
|
+
- s2-rm output 3 -> control-type node input (so it can resolve its instructions)
|
|
59
|
+
- control-type node's command output -> s2-rm input (routes `UpdateStatus`/`SystemDescription`/`PowerConstraints`/`InstructionStatus` commands back through s2-rm)
|
|
60
|
+
|
|
61
|
+
`s2-ombc` and `s2-pebc` can be wired in parallel downstream of the same `s2-rm` - each passes through instructions meant for the other control type unchanged.
|
|
62
|
+
|
|
63
|
+
If you're sending PowerForecasts and using `s2-pebc`, route your Forecast command into `s2-pebc`'s input too (instead of directly into s2-rm) - see [Sending PowerForecasts](#sending-powerforecasts).
|
|
64
|
+
|
|
65
|
+
See `examples/boiler-ombc-demo.json` for a complete working OMBC flow.
|
|
50
66
|
|
|
51
67
|
## Sending PowerMeasurements
|
|
52
68
|
|
|
@@ -66,6 +82,15 @@ To send power measurements to the CEM, inject a message into the s2-rm input:
|
|
|
66
82
|
|
|
67
83
|
The s2-rm node emits a `PowerMeasurementStart` signal on output 1 when the CEM selects a control type, so you can use that to trigger periodic measurements.
|
|
68
84
|
|
|
85
|
+
### Direction-aware limiting with s2-pebc
|
|
86
|
+
|
|
87
|
+
A PEBC power envelope can be asymmetric (different import and export bounds), but many devices only expose a single settable limit. If your `s2-pebc` node's input is also wired to your `PowerMeasurement` command (in addition to wherever else it already goes - no changes needed to what you send to `s2-rm`), it tracks your last measurement's sign and adds two fields to its active-element output:
|
|
88
|
+
|
|
89
|
+
- `direction`: `'import'` or `'export'`, from the sign of your last measurement for that commodity (defaults to `'import'` if none has been seen yet).
|
|
90
|
+
- `limitW`: the magnitude, in watts, of whichever bound applies - `upperBound` for import, `|lowerBound|` for export (or `null` if that bound is unbounded).
|
|
91
|
+
|
|
92
|
+
Apply `limitW` to your single actuator instead of always using `upperBound`. If your measurement's direction flips mid-slot on an asymmetric bound, `s2-pebc` re-emits output 1 with the updated values (without resending `InstructionStatus`, since the instruction itself hasn't changed) - so a flow reading `limitW` stays correct as flow direction changes, not just at the start of each slot.
|
|
93
|
+
|
|
69
94
|
## Sending PowerForecasts
|
|
70
95
|
|
|
71
96
|
```json
|
|
@@ -88,13 +113,16 @@ The s2-rm node emits a `PowerMeasurementStart` signal on output 1 when the CEM s
|
|
|
88
113
|
}
|
|
89
114
|
```
|
|
90
115
|
|
|
116
|
+
If a `s2-pebc` node is present, inject this into its input instead of directly into `s2-rm` - `s2-pebc` caps `forecast.elements` to its currently accumulated PEBC schedule (tightest overlapping bound per element) before forwarding the command to `s2-rm` on its output 3. With no accumulated schedule, or without `s2-pebc` in the path, the forecast is forwarded/sent unchanged.
|
|
117
|
+
|
|
91
118
|
## Updating PEBC PowerConstraints
|
|
92
119
|
|
|
120
|
+
`s2-pebc` pushes a default constraints range on deploy (derived from its `s2-pebc-config`). To override it at runtime, inject a message into the s2-rm input - unlike every other command, `PowerConstraints` applies globally and does not require a `cemId`:
|
|
121
|
+
|
|
93
122
|
```json
|
|
94
123
|
{
|
|
95
124
|
"payload": {
|
|
96
125
|
"command": "PowerConstraints",
|
|
97
|
-
"cemId": "cem",
|
|
98
126
|
"constraints": {
|
|
99
127
|
"commodityQuantity": "ELECTRIC.POWER.3_PHASE_SYMMETRIC",
|
|
100
128
|
"minPower": -3000,
|
|
@@ -104,7 +132,7 @@ The s2-rm node emits a `PowerMeasurementStart` signal on output 1 when the CEM s
|
|
|
104
132
|
}
|
|
105
133
|
```
|
|
106
134
|
|
|
107
|
-
Constraints are stored at the node level and automatically sent
|
|
135
|
+
Constraints are stored at the node level and automatically (re-)sent whenever a CEM selects PEBC.
|
|
108
136
|
|
|
109
137
|
## Development
|
|
110
138
|
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { S2Session, State } from './s2/session';
|
|
2
|
-
export type { StateValue, S2SessionOptions,
|
|
2
|
+
export type { StateValue, S2SessionOptions, StatusPayload, SystemDescriptionPayload } from './s2/session';
|
|
3
3
|
export { MessageType, ControlType, ReceptionStatusResult, parse, serialize, makeReceptionStatus, makeHandshake, makeResourceManagerDetails, generateId } from './s2/messages';
|
|
4
4
|
export type { MessageTypeValue, ControlTypeValue, ReceptionStatusResultValue, S2IncomingMessage, S2Role, PowerMeasurementValue, RmDetails } from './s2/messages';
|
|
@@ -23,8 +23,9 @@ export declare function parsePebcInstruction(msg: Record<string, unknown>, recei
|
|
|
23
23
|
*/
|
|
24
24
|
export declare function getActiveElement(schedule: PebcSchedule, nowMs: number): ScheduleElement | null;
|
|
25
25
|
/**
|
|
26
|
-
* Return the start time (ms) of the element
|
|
27
|
-
*
|
|
26
|
+
* Return the start time (ms) of the next element to activate after nowMs - the
|
|
27
|
+
* soonest startMs still in the future, whether or not an element is currently
|
|
28
|
+
* active - or null if there is none.
|
|
28
29
|
*/
|
|
29
30
|
export declare function getNextElementStart(schedule: PebcSchedule, nowMs: number): number | null;
|
|
30
31
|
/**
|
package/dist/lib/s2/schedule.js
CHANGED
|
@@ -51,16 +51,17 @@ function getActiveElement(schedule, nowMs) {
|
|
|
51
51
|
return null;
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
54
|
-
* Return the start time (ms) of the element
|
|
55
|
-
*
|
|
54
|
+
* Return the start time (ms) of the next element to activate after nowMs - the
|
|
55
|
+
* soonest startMs still in the future, whether or not an element is currently
|
|
56
|
+
* active - or null if there is none.
|
|
56
57
|
*/
|
|
57
58
|
function getNextElementStart(schedule, nowMs) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (
|
|
61
|
-
|
|
59
|
+
let next = null;
|
|
60
|
+
for (const el of schedule.elements) {
|
|
61
|
+
if (el.startMs > nowMs && (next === null || el.startMs < next))
|
|
62
|
+
next = el.startMs;
|
|
62
63
|
}
|
|
63
|
-
return
|
|
64
|
+
return next;
|
|
64
65
|
}
|
|
65
66
|
/**
|
|
66
67
|
* Return a copy of forecast with value_expected (and value_upper/lower_limit when present)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schedule.js","sourceRoot":"","sources":["../../../src/lib/s2/schedule.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAoCZ,oDA+BC;AAKD,4CAKC;
|
|
1
|
+
{"version":3,"file":"schedule.js","sourceRoot":"","sources":["../../../src/lib/s2/schedule.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/s2/session.d.ts
CHANGED
|
@@ -7,18 +7,19 @@ export declare const State: Readonly<{
|
|
|
7
7
|
readonly CONNECTED: "CONNECTED";
|
|
8
8
|
}>;
|
|
9
9
|
export type StateValue = (typeof State)[keyof typeof State];
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
/** Control-type-namespaced status payload, e.g. `{ ombc: OMBCStatusConfig }`. */
|
|
11
|
+
export interface StatusPayload {
|
|
12
|
+
ombc?: OMBCStatusConfig;
|
|
13
|
+
[key: string]: unknown;
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
/** Control-type-namespaced system description payload, e.g. `{ ombc: OMBCSystemDescriptionConfig }`. */
|
|
16
|
+
export interface SystemDescriptionPayload {
|
|
17
|
+
ombc?: OMBCSystemDescriptionConfig;
|
|
16
18
|
[key: string]: unknown;
|
|
17
19
|
}
|
|
18
20
|
export interface S2SessionOptions {
|
|
19
21
|
cemId: string;
|
|
20
22
|
rmDetails?: RmDetails;
|
|
21
|
-
controlTypeConfig?: ControlTypeConfig;
|
|
22
23
|
onSend?: (msg: object) => void;
|
|
23
24
|
onStateChange?: (state: StateValue) => void;
|
|
24
25
|
onMessage?: (msg: S2IncomingMessage) => void;
|
|
@@ -42,12 +43,6 @@ export interface S2SessionOptions {
|
|
|
42
43
|
* const session = new S2Session({
|
|
43
44
|
* cemId,
|
|
44
45
|
* rmDetails,
|
|
45
|
-
* controlTypeConfig: { // optional control type configuration
|
|
46
|
-
* OMBC: {
|
|
47
|
-
* systemDescription: { operationModes: [...], transitions: [], timers: [] },
|
|
48
|
-
* status: { activeOperationModeId: 'mode-1', operationModeFactor: 1 }
|
|
49
|
-
* }
|
|
50
|
-
* },
|
|
51
46
|
* onSend: (msg) => <send S2 message object to CEM>,
|
|
52
47
|
* onStateChange: (state) => ...,
|
|
53
48
|
* onMessage: (msg) => <forward received message downstream>,
|
|
@@ -61,7 +56,6 @@ export interface S2SessionOptions {
|
|
|
61
56
|
export declare class S2Session {
|
|
62
57
|
private readonly _cemId;
|
|
63
58
|
private readonly _rmDetails;
|
|
64
|
-
private readonly _controlTypeConfig;
|
|
65
59
|
private readonly _onSend;
|
|
66
60
|
private readonly _onStateChange;
|
|
67
61
|
private readonly _onMessage;
|
|
@@ -75,13 +69,11 @@ export declare class S2Session {
|
|
|
75
69
|
private _selectedControlType;
|
|
76
70
|
private _lastKeepAlive;
|
|
77
71
|
private _pebcPowerConstraints;
|
|
78
|
-
|
|
79
|
-
constructor({ cemId, rmDetails, controlTypeConfig, onSend, onStateChange, onMessage, onInstruction, onError, retryDelayMs, skipInstructionStatus }: S2SessionOptions);
|
|
72
|
+
constructor({ cemId, rmDetails, onSend, onStateChange, onMessage, onInstruction, onError, retryDelayMs, skipInstructionStatus }: S2SessionOptions);
|
|
80
73
|
get cemId(): string;
|
|
81
74
|
get state(): StateValue;
|
|
82
75
|
get selectedControlType(): ControlTypeValue | string;
|
|
83
76
|
get lastKeepAlive(): Date | null;
|
|
84
|
-
get currentOMBCStatus(): OMBCStatusConfig | null;
|
|
85
77
|
/**
|
|
86
78
|
* Cancel pending retry timers and clear the sent-message buffer.
|
|
87
79
|
* Call when the session is no longer needed (disconnect, node close).
|
|
@@ -111,12 +103,16 @@ export declare class S2Session {
|
|
|
111
103
|
*/
|
|
112
104
|
setPEBCPowerConstraints(input: PEBCPowerConstraintsInput): void;
|
|
113
105
|
/**
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
106
|
+
* Send a control-type-namespaced status message to the CEM.
|
|
107
|
+
* The control-type node (e.g. s2-ombc) owns tracking of the previous
|
|
108
|
+
* value and any transition timestamp - this just dispatches to the
|
|
109
|
+
* matching S2 status message and sends it when CONNECTED.
|
|
110
|
+
*/
|
|
111
|
+
updateStatus(controlType: ControlTypeValue | string, payload: StatusPayload): void;
|
|
112
|
+
/**
|
|
113
|
+
* Send a control-type-namespaced system description message to the CEM.
|
|
118
114
|
*/
|
|
119
|
-
|
|
115
|
+
sendSystemDescription(controlType: ControlTypeValue | string, payload: SystemDescriptionPayload): void;
|
|
120
116
|
/**
|
|
121
117
|
* Send an InstructionStatusUpdate for an instruction previously received from the CEM.
|
|
122
118
|
* Use this to report STARTED, SUCCEEDED, ABORTED, etc. after ACCEPTED was auto-sent.
|
|
@@ -133,6 +129,5 @@ export declare class S2Session {
|
|
|
133
129
|
private _setState;
|
|
134
130
|
private _handleHandshakeResponse;
|
|
135
131
|
private _handleSelectControlType;
|
|
136
|
-
private _sendOMBCSystemDescriptionAndStatus;
|
|
137
132
|
private _ackAndForward;
|
|
138
133
|
}
|
package/dist/lib/s2/session.js
CHANGED
|
@@ -21,12 +21,6 @@ exports.State = Object.freeze({
|
|
|
21
21
|
* const session = new S2Session({
|
|
22
22
|
* cemId,
|
|
23
23
|
* rmDetails,
|
|
24
|
-
* controlTypeConfig: { // optional control type configuration
|
|
25
|
-
* OMBC: {
|
|
26
|
-
* systemDescription: { operationModes: [...], transitions: [], timers: [] },
|
|
27
|
-
* status: { activeOperationModeId: 'mode-1', operationModeFactor: 1 }
|
|
28
|
-
* }
|
|
29
|
-
* },
|
|
30
24
|
* onSend: (msg) => <send S2 message object to CEM>,
|
|
31
25
|
* onStateChange: (state) => ...,
|
|
32
26
|
* onMessage: (msg) => <forward received message downstream>,
|
|
@@ -38,11 +32,9 @@ exports.State = Object.freeze({
|
|
|
38
32
|
* session.send(msg) // send an outbound S2 message (only when CONNECTED)
|
|
39
33
|
*/
|
|
40
34
|
class S2Session {
|
|
41
|
-
constructor({ cemId, rmDetails,
|
|
42
|
-
var _a, _b;
|
|
35
|
+
constructor({ cemId, rmDetails, onSend, onStateChange, onMessage, onInstruction, onError, retryDelayMs, skipInstructionStatus }) {
|
|
43
36
|
this._cemId = cemId;
|
|
44
37
|
this._rmDetails = rmDetails;
|
|
45
|
-
this._controlTypeConfig = controlTypeConfig || {};
|
|
46
38
|
this._onSend = onSend || (() => { });
|
|
47
39
|
this._onStateChange = onStateChange || (() => { });
|
|
48
40
|
this._onMessage = onMessage || (() => { });
|
|
@@ -56,13 +48,11 @@ class S2Session {
|
|
|
56
48
|
this._selectedControlType = messages_1.ControlType.NO_SELECTION;
|
|
57
49
|
this._lastKeepAlive = null;
|
|
58
50
|
this._pebcPowerConstraints = null;
|
|
59
|
-
this._currentOMBCStatus = (_b = (_a = this._controlTypeConfig.OMBC) === null || _a === void 0 ? void 0 : _a.status) !== null && _b !== void 0 ? _b : null;
|
|
60
51
|
}
|
|
61
52
|
get cemId() { return this._cemId; }
|
|
62
53
|
get state() { return this._state; }
|
|
63
54
|
get selectedControlType() { return this._selectedControlType; }
|
|
64
55
|
get lastKeepAlive() { return this._lastKeepAlive; }
|
|
65
|
-
get currentOMBCStatus() { return this._currentOMBCStatus; }
|
|
66
56
|
/**
|
|
67
57
|
* Cancel pending retry timers and clear the sent-message buffer.
|
|
68
58
|
* Call when the session is no longer needed (disconnect, node close).
|
|
@@ -189,24 +179,31 @@ class S2Session {
|
|
|
189
179
|
}
|
|
190
180
|
}
|
|
191
181
|
/**
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
182
|
+
* Send a control-type-namespaced status message to the CEM.
|
|
183
|
+
* The control-type node (e.g. s2-ombc) owns tracking of the previous
|
|
184
|
+
* value and any transition timestamp - this just dispatches to the
|
|
185
|
+
* matching S2 status message and sends it when CONNECTED.
|
|
196
186
|
*/
|
|
197
|
-
|
|
198
|
-
if (
|
|
199
|
-
this.
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
transitionTimestamp: new Date().toISOString()
|
|
204
|
-
};
|
|
187
|
+
updateStatus(controlType, payload) {
|
|
188
|
+
if (controlType === messages_1.ControlType.OMBC && payload.ombc) {
|
|
189
|
+
if (this._state === exports.State.CONNECTED) {
|
|
190
|
+
this._send((0, messages_1.makeOMBCStatus)(payload.ombc));
|
|
191
|
+
}
|
|
192
|
+
return;
|
|
205
193
|
}
|
|
206
|
-
this.
|
|
207
|
-
|
|
208
|
-
|
|
194
|
+
this._onError(new Error(`No status message available for control type ${controlType}`));
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Send a control-type-namespaced system description message to the CEM.
|
|
198
|
+
*/
|
|
199
|
+
sendSystemDescription(controlType, payload) {
|
|
200
|
+
if (controlType === messages_1.ControlType.OMBC && payload.ombc) {
|
|
201
|
+
if (this._state === exports.State.CONNECTED) {
|
|
202
|
+
this._send((0, messages_1.makeOMBCSystemDescription)(payload.ombc));
|
|
203
|
+
}
|
|
204
|
+
return;
|
|
209
205
|
}
|
|
206
|
+
this._onError(new Error(`No system description message available for control type ${controlType}`));
|
|
210
207
|
}
|
|
211
208
|
/**
|
|
212
209
|
* Send an InstructionStatusUpdate for an instruction previously received from the CEM.
|
|
@@ -255,28 +252,13 @@ class S2Session {
|
|
|
255
252
|
this._selectedControlType = msg.control_type || messages_1.ControlType.NO_SELECTION;
|
|
256
253
|
this._send((0, messages_1.makeReceptionStatus)(msg.message_id, messages_1.ReceptionStatusResult.OK));
|
|
257
254
|
this._onMessage(msg);
|
|
258
|
-
//
|
|
255
|
+
// System description and status for the selected control type are no longer
|
|
256
|
+
// sent automatically here - the matching control-type node (e.g. s2-ombc)
|
|
257
|
+
// observes this message on s2-rm's "from CEM" output and pushes them back
|
|
258
|
+
// via the SystemDescription/UpdateStatus commands.
|
|
259
259
|
const controlType = msg.control_type;
|
|
260
|
-
if (controlType === messages_1.ControlType.
|
|
261
|
-
this.
|
|
262
|
-
}
|
|
263
|
-
else if (controlType === messages_1.ControlType.PEBC) {
|
|
264
|
-
if (this._pebcPowerConstraints) {
|
|
265
|
-
this._send((0, messages_1.makePEBCPowerConstraints)(this._pebcPowerConstraints));
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
_sendOMBCSystemDescriptionAndStatus() {
|
|
270
|
-
const config = this._controlTypeConfig.OMBC;
|
|
271
|
-
if (!config) {
|
|
272
|
-
this._onError(new Error(`No OMBC config for CEM ${this._cemId} - set Control Type Config in the s2-rm node`));
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
if (config.systemDescription) {
|
|
276
|
-
this._send((0, messages_1.makeOMBCSystemDescription)(config.systemDescription));
|
|
277
|
-
}
|
|
278
|
-
if (this._currentOMBCStatus) {
|
|
279
|
-
this._send((0, messages_1.makeOMBCStatus)(this._currentOMBCStatus));
|
|
260
|
+
if (controlType === messages_1.ControlType.PEBC && this._pebcPowerConstraints) {
|
|
261
|
+
this._send((0, messages_1.makePEBCPowerConstraints)(this._pebcPowerConstraints));
|
|
280
262
|
}
|
|
281
263
|
}
|
|
282
264
|
_ackAndForward(msg) {
|
|
@@ -285,18 +267,6 @@ class S2Session {
|
|
|
285
267
|
if (typeof instructionId === 'string' && !this._skipInstructionStatus) {
|
|
286
268
|
this._send((0, messages_1.makeInstructionStatusUpdate)(instructionId, messages_1.InstructionStatus.ACCEPTED));
|
|
287
269
|
}
|
|
288
|
-
// For OMBC instructions: send OMBC.Status immediately at accept time.
|
|
289
|
-
// transition_timestamp is set to now (initiation time) by updateOMBCStatus when the mode changes.
|
|
290
|
-
if (msg.message_type === messages_1.MessageType.OMBC_INSTRUCTION) {
|
|
291
|
-
const modeId = msg.operation_mode_id;
|
|
292
|
-
const factor = msg.operation_mode_factor;
|
|
293
|
-
if (modeId) {
|
|
294
|
-
this.updateOMBCStatus({
|
|
295
|
-
activeOperationModeId: modeId,
|
|
296
|
-
operationModeFactor: typeof factor === 'number' ? factor : 1
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
270
|
this._onInstruction(msg);
|
|
301
271
|
}
|
|
302
272
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/lib/s2/session.ts"],"names":[],"mappings":";;;AAAA,yCAoBmB;AAEnB;;GAEG;AACU,QAAA,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC;IACjC,WAAW,EAAE,aAAa,EAAE,+DAA+D;IAC3F,SAAS,EAAE,WAAW,CAAC,6CAA6C;CAC5D,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/lib/s2/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -51,4 +51,14 @@
|
|
|
51
51
|
</div>
|
|
52
52
|
</script>
|
|
53
53
|
|
|
54
|
+
<script type="text/html" data-help-name="s2-cem-config">
|
|
55
|
+
<p>Configuration for connecting to a CEM: the WebSocket URL and (optional) credentials used by <b>s2-websocket</b>, plus the REST API location <b>s2-rm</b> derives flex-instruction URLs from.</p>
|
|
56
|
+
|
|
57
|
+
<p><b>CEM URL</b> is the WebSocket endpoint. Either include <code>{resourceId}</code> as a placeholder in the URL, or end it with a trailing slash and the Resource ID (from the paired <b>s2-rm-config</b>) is appended automatically.</p>
|
|
58
|
+
|
|
59
|
+
<p><b>API Prefix</b> is used only to build the CEM's REST API base URL, published to flow context as <code>flow.cemFlexInstructionUrl</code> (and <code>flow.cemApiAuth</code>, if Username is set) by <b>s2-rm</b>. It's derived from the WebSocket URL's host with the WebSocket path dropped and this prefix appended instead - set it when the REST API lives under a different path than the WebSocket endpoint (e.g. the WebSocket is at <code>/s2-message-handler/ws</code> but the REST API is at <code>/s2-message-handler/resource_managers/...</code>, needing prefix <code>/s2-message-handler</code>). Leave empty if the REST API is at the host root, or if you don't use the CEM's REST API at all.</p>
|
|
60
|
+
|
|
61
|
+
<p><b>Username</b>/<b>Password</b> are optional HTTP Basic credentials. <b>s2-websocket</b> sends them as an <code>Authorization</code> header on the WebSocket connection itself; <b>s2-rm</b> also publishes the same header value as <code>flow.cemApiAuth</code> for use against the REST API above.</p>
|
|
62
|
+
</script>
|
|
63
|
+
|
|
54
64
|
<link rel="stylesheet" href="resources/node-red-contrib-s2/s2-styles.css">
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1042 1042" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
|
2
|
+
<g transform="matrix(1,0,0,1,-312,-142)">
|
|
3
|
+
<g transform="matrix(1038.75,-1038.75,-1038.75,-1038.75,314.531,1181.19)">
|
|
4
|
+
<path d="M0.75,0.251C0.739,0.262 0.727,0.272 0.715,0.281C0.708,0.286 0.701,0.291 0.694,0.296C0.65,0.325 0.6,0.344 0.549,0.351C0.516,0.356 0.482,0.356 0.449,0.351C0.398,0.344 0.348,0.325 0.303,0.296C0.284,0.283 0.265,0.268 0.248,0.251C0.22,0.223 0.22,0.178 0.248,0.15C0.276,0.123 0.321,0.123 0.348,0.15C0.366,0.168 0.386,0.182 0.407,0.192C0.465,0.22 0.533,0.22 0.591,0.192C0.612,0.182 0.632,0.168 0.649,0.15L0.758,0.042C0.773,0.027 0.789,0.015 0.806,0.006C0.821,-0.003 0.837,-0.009 0.853,-0.013C0.902,-0.026 0.954,-0.022 1,-0L0.75,0.251ZM0.525,0.115C0.499,0.112 0.482,0.097 0.474,0.088C0.465,0.078 0.466,0.062 0.477,0.052C0.487,0.043 0.503,0.044 0.513,0.054C0.515,0.057 0.521,0.063 0.531,0.064C0.541,0.065 0.551,0.061 0.557,0.052C0.564,0.042 0.564,0.026 0.556,0.016C0.549,0.008 0.538,0.006 0.535,0.005L0.33,-0.014L0.447,-0.132C0.457,-0.142 0.474,-0.142 0.483,-0.132C0.493,-0.122 0.493,-0.106 0.483,-0.096L0.443,-0.055L0.541,-0.045C0.551,-0.044 0.577,-0.039 0.596,-0.015C0.618,0.013 0.619,0.052 0.599,0.081C0.596,0.085 0.593,0.089 0.59,0.092C0.573,0.109 0.549,0.118 0.525,0.115ZM0.649,-0.15C0.632,-0.168 0.612,-0.182 0.591,-0.192C0.533,-0.22 0.465,-0.22 0.407,-0.192C0.386,-0.182 0.366,-0.168 0.348,-0.15L0.24,-0.042C0.225,-0.027 0.209,-0.015 0.192,-0.006C0.177,0.003 0.161,0.009 0.145,0.013C0.096,0.026 0.044,0.022 -0.003,0L0.248,-0.251C0.259,-0.262 0.271,-0.272 0.282,-0.281C0.289,-0.286 0.296,-0.291 0.303,-0.296C0.348,-0.325 0.398,-0.344 0.449,-0.351C0.482,-0.356 0.516,-0.356 0.549,-0.351C0.6,-0.344 0.65,-0.325 0.694,-0.296C0.714,-0.283 0.732,-0.268 0.75,-0.251C0.777,-0.223 0.777,-0.178 0.75,-0.15C0.722,-0.123 0.677,-0.123 0.649,-0.15Z" style="fill:url(#s2logo-gradient);fill-rule:nonzero;"/>
|
|
5
|
+
</g>
|
|
6
|
+
</g>
|
|
7
|
+
<defs>
|
|
8
|
+
<linearGradient id="s2logo-gradient" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,-1,0,3.73045e-07)">
|
|
9
|
+
<stop offset="0" style="stop-color:rgb(45,19,75);stop-opacity:1"/>
|
|
10
|
+
<stop offset="0.37" style="stop-color:rgb(25,38,101);stop-opacity:1"/>
|
|
11
|
+
<stop offset="1" style="stop-color:rgb(17,88,163);stop-opacity:1"/>
|
|
12
|
+
</linearGradient>
|
|
13
|
+
</defs>
|
|
14
|
+
</svg>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { NodeRedApp } from '../../types/node-red';
|
|
2
|
+
/**
|
|
3
|
+
* s2-ombc node
|
|
4
|
+
*
|
|
5
|
+
* Owns OMBC-specific S2 protocol behavior: declares the OMBC system description,
|
|
6
|
+
* resolves OMBC instructions into actionable output, and confirms operation mode
|
|
7
|
+
* changes back to the CEM once told the hardware state is confirmed.
|
|
8
|
+
*
|
|
9
|
+
* Wiring:
|
|
10
|
+
* [s2-rm output 2 (from CEM)] -> [s2-ombc input] (to observe SelectControlType)
|
|
11
|
+
* [s2-rm output 3 (instructions)] -> [s2-ombc input] (to resolve OMBC instructions)
|
|
12
|
+
* [confirm-mode message] -> [s2-ombc input] (see Input below)
|
|
13
|
+
* [s2-ombc output 1] -> downstream flow (resolved/pass-through instructions)
|
|
14
|
+
* [s2-ombc output 2] -> [s2-rm input] (SystemDescription / UpdateStatus commands)
|
|
15
|
+
*
|
|
16
|
+
* Input:
|
|
17
|
+
* S2 "from CEM" messages and enriched instructions forwarded from s2-rm, as-is.
|
|
18
|
+
* Confirm-mode message (from your own flow, once hardware state is confirmed):
|
|
19
|
+
* { payload: { confirmedOperationModeId: <id>, operationModeFactor?: <number> }, cemId: <string> }
|
|
20
|
+
*
|
|
21
|
+
* Output port 1 - instructions:
|
|
22
|
+
* OMBC instructions resolved: { payload, cemId, controlType, topic: <mode label>, ombc: { operationMode: {...}, ... } }
|
|
23
|
+
* Non-OMBC instructions: passed through unchanged (node status shows a warning).
|
|
24
|
+
*
|
|
25
|
+
* Output port 2 - commands to s2-rm:
|
|
26
|
+
* { payload: { command: 'SystemDescription', cemId, controlType, ombc } }
|
|
27
|
+
* { payload: { command: 'UpdateStatus', cemId, controlType, ombc } }
|
|
28
|
+
*/
|
|
29
|
+
declare const _default: (RED: NodeRedApp) => void;
|
|
30
|
+
export = _default;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<script src="resources/node-red-contrib-s2/s2-common.js"></script>
|
|
2
|
+
<script type="text/javascript">
|
|
3
|
+
RED.nodes.registerType('s2-ombc', {
|
|
4
|
+
category: 's2',
|
|
5
|
+
color: '#5A8EC2',
|
|
6
|
+
defaults: {
|
|
7
|
+
name: { value: '' },
|
|
8
|
+
ombcConfig: { value: '', type: 's2-ombc-config', required: true }
|
|
9
|
+
},
|
|
10
|
+
inputs: 1,
|
|
11
|
+
outputs: 2,
|
|
12
|
+
icon: 's2-logo.svg',
|
|
13
|
+
outputLabels: ['instructions', 'to s2-rm'],
|
|
14
|
+
inputLabels: ['from s2-rm / confirm-mode'],
|
|
15
|
+
label: function () {
|
|
16
|
+
return this.name || 's2-ombc'
|
|
17
|
+
},
|
|
18
|
+
labelStyle: function () {
|
|
19
|
+
return this.name ? 'node_label_italic' : ''
|
|
20
|
+
},
|
|
21
|
+
oneditprepare: function () {
|
|
22
|
+
window.__s2Common.initializeTooltips()
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<script type="text/html" data-template-name="s2-ombc">
|
|
28
|
+
<div class="s2-form">
|
|
29
|
+
|
|
30
|
+
<div class="form-row">
|
|
31
|
+
<label for="node-input-name">
|
|
32
|
+
<i class="fa fa-tag"></i> Name
|
|
33
|
+
</label>
|
|
34
|
+
<input type="text" id="node-input-name" placeholder="Name (optional)">
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<div class="form-row">
|
|
38
|
+
<label for="node-input-ombcConfig"><i class="fa fa-id-card"></i> OMBC Config<i class="fa fa-info-circle tooltip-icon" data-tooltip="OMBC system description (operation modes, transitions, timers)."></i></label>
|
|
39
|
+
<input type="text" id="node-input-ombcConfig">
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
</div>
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<link rel="stylesheet" href="resources/node-red-contrib-s2/s2-styles.css">
|
|
46
|
+
|
|
47
|
+
<script type="text/html" data-help-name="s2-ombc">
|
|
48
|
+
<p>Owns Operation Mode Based Control (OMBC) behavior: declares the OMBC system description to the CEM, resolves OMBC instructions, and confirms operation mode changes back to the CEM once told the hardware state is confirmed.</p>
|
|
49
|
+
<p>Wire this node's input to both <b>s2-rm</b>'s "from CEM" output (to observe <code>SelectControlType</code>) and its "instructions" output (to resolve OMBC instructions). Wire this node's second output back to <b>s2-rm</b>'s input.</p>
|
|
50
|
+
<h3>Input</h3>
|
|
51
|
+
<dl class="message-properties">
|
|
52
|
+
<dt>payload <span class="property-type">object</span></dt>
|
|
53
|
+
<dd>S2 "from CEM" messages and enriched instructions forwarded from <b>s2-rm</b>, as-is.</dd>
|
|
54
|
+
</dl>
|
|
55
|
+
<p>Confirm-mode message, sent from your own flow once the hardware state matches the requested mode:</p>
|
|
56
|
+
<dl class="message-properties">
|
|
57
|
+
<dt>payload.confirmedOperationModeId <span class="property-type">string</span></dt>
|
|
58
|
+
<dd>Id of the operation mode now active on the hardware.</dd>
|
|
59
|
+
<dt>payload.operationModeFactor <span class="property-type">number</span></dt>
|
|
60
|
+
<dd>Optional. Defaults to 1.</dd>
|
|
61
|
+
<dt>cemId <span class="property-type">string</span></dt>
|
|
62
|
+
<dd>Required. The CEM this confirmation applies to.</dd>
|
|
63
|
+
</dl>
|
|
64
|
+
<h3>Outputs</h3>
|
|
65
|
+
<ol class="node-ports">
|
|
66
|
+
<li>Instructions
|
|
67
|
+
<dl class="message-properties">
|
|
68
|
+
<dt>topic <span class="property-type">string</span></dt>
|
|
69
|
+
<dd>Resolved mode's diagnostic label, for routing with a Switch node. Only set for resolved OMBC instructions.</dd>
|
|
70
|
+
<dt>ombc.operationMode <span class="property-type">object</span></dt>
|
|
71
|
+
<dd><code>{ id, index, label, factor, powerRanges }</code> for the resolved mode.</dd>
|
|
72
|
+
</dl>
|
|
73
|
+
Non-OMBC instructions are passed through unchanged (node status shows a warning), so this node can be wired in parallel with s2-pebc downstream of the same s2-rm.
|
|
74
|
+
</li>
|
|
75
|
+
<li>To s2-rm
|
|
76
|
+
<dl class="message-properties">
|
|
77
|
+
<dt>payload <span class="property-type">object</span></dt>
|
|
78
|
+
<dd><code>{ command: 'SystemDescription', cemId, controlType, ombc }</code> or <code>{ command: 'UpdateStatus', cemId, controlType, ombc }</code>. Wire to s2-rm's input.</dd>
|
|
79
|
+
</dl>
|
|
80
|
+
</li>
|
|
81
|
+
</ol>
|
|
82
|
+
</script>
|