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
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
6
|
+
|
|
7
|
+
## [0.1.0]
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `s2-rm` node: S2 Resource Manager session handling (handshake, control type selection, instructions).
|
|
12
|
+
- `s2-rm-config` / `s2-cem-config` nodes for RM identity and CEM connection configuration.
|
|
13
|
+
- `s2-websocket` node: WebSocket transport to a CEM, with reconnect/backoff handling.
|
|
14
|
+
- Operation Mode Based Control (OMBC) and Power Envelope Based Control (PEBC) support.
|
|
15
|
+
- PowerMeasurement and PowerForecast forwarding.
|
|
16
|
+
- Multiple concurrent CEM sessions.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Victron Energy BV
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# node-red-contrib-s2
|
|
2
|
+
|
|
3
|
+
Node-RED nodes for the [S2 energy management protocol](https://s2standard.org/) (EN 50491-12-2).
|
|
4
|
+
|
|
5
|
+
S2 is a European standard for demand-side energy flexibility. It defines how a Customer Energy Manager (CEM) communicates with Resource Managers (RMs) to coordinate energy consumption, production, and storage.
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
- Node-RED >= 4.1.0
|
|
10
|
+
- Node.js >= 24
|
|
11
|
+
|
|
12
|
+
## Nodes
|
|
13
|
+
|
|
14
|
+
| Node | Description |
|
|
15
|
+
|------|-------------|
|
|
16
|
+
| **s2-rm** | S2 Resource Manager - manages protocol sessions with one or more CEMs |
|
|
17
|
+
| **s2-rm-config** | Configuration for RM identity: resource ID, name, roles, control types, serial number |
|
|
18
|
+
| **s2-cem-config** | Configuration for CEM connection (WebSocket URL and credentials) |
|
|
19
|
+
| **s2-websocket** | WebSocket transport for S2 communication with a CEM |
|
|
20
|
+
|
|
21
|
+
## Features
|
|
22
|
+
|
|
23
|
+
- S2 protocol handshake and session management
|
|
24
|
+
- Operation Mode Based Control (OMBC)
|
|
25
|
+
- Power Envelope Based Control (PEBC) with configurable power constraints
|
|
26
|
+
- PowerMeasurement forwarding (3-phase symmetric or per-phase L1/L2/L3)
|
|
27
|
+
- PowerForecast support
|
|
28
|
+
- Multiple concurrent CEM sessions
|
|
29
|
+
- Configurable RM roles (Consumer, Producer, Storage)
|
|
30
|
+
- Context variable templates in serial number (e.g. `{{global.vrmId}}`)
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
Install via the Node-RED palette manager, or from the command line:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
cd ~/.node-red
|
|
38
|
+
npm install node-red-contrib-s2
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Quick start
|
|
42
|
+
|
|
43
|
+
1. Add an **s2-rm-config** node and configure your Resource Manager identity (name, roles, control types).
|
|
44
|
+
2. Add an **s2-cem-config** node with the WebSocket URL and credentials of your CEM.
|
|
45
|
+
3. Wire an **s2-websocket** node to an **s2-rm** node:
|
|
46
|
+
- s2-websocket output 2 -> s2-rm input
|
|
47
|
+
- 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. PEBC.Instruction, OMBC.Instruction).
|
|
50
|
+
|
|
51
|
+
## Sending PowerMeasurements
|
|
52
|
+
|
|
53
|
+
To send power measurements to the CEM, inject a message into the s2-rm input:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"payload": {
|
|
58
|
+
"command": "PowerMeasurement",
|
|
59
|
+
"cemId": "cem",
|
|
60
|
+
"values": [
|
|
61
|
+
{ "commodity_quantity": "ELECTRIC.POWER.3_PHASE_SYMMETRIC", "value": 1500 }
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
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
|
+
|
|
69
|
+
## Sending PowerForecasts
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"payload": {
|
|
74
|
+
"command": "Forecast",
|
|
75
|
+
"cemId": "cem",
|
|
76
|
+
"forecast": {
|
|
77
|
+
"startTime": "2026-04-14T10:00:00Z",
|
|
78
|
+
"elements": [
|
|
79
|
+
{
|
|
80
|
+
"duration": 900000,
|
|
81
|
+
"power_values": [
|
|
82
|
+
{ "commodity_quantity": "ELECTRIC.POWER.3_PHASE_SYMMETRIC", "value_expected": 1500 }
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Updating PEBC PowerConstraints
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"payload": {
|
|
96
|
+
"command": "PowerConstraints",
|
|
97
|
+
"cemId": "cem",
|
|
98
|
+
"constraints": {
|
|
99
|
+
"commodityQuantity": "ELECTRIC.POWER.3_PHASE_SYMMETRIC",
|
|
100
|
+
"minPower": -3000,
|
|
101
|
+
"maxPower": 3000
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Constraints are stored at the node level and automatically sent when a CEM selects PEBC.
|
|
108
|
+
|
|
109
|
+
## Development
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
npm install
|
|
113
|
+
npm run build
|
|
114
|
+
npm test
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## License
|
|
118
|
+
|
|
119
|
+
[MIT](LICENSE) - Copyright (c) 2026 Victron Energy BV
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { S2Session, State } from './s2/session';
|
|
2
|
+
export type { StateValue, S2SessionOptions, ControlTypeConfig } from './s2/session';
|
|
3
|
+
export { MessageType, ControlType, ReceptionStatusResult, parse, serialize, makeReceptionStatus, makeHandshake, makeResourceManagerDetails, generateId } from './s2/messages';
|
|
4
|
+
export type { MessageTypeValue, ControlTypeValue, ReceptionStatusResultValue, S2IncomingMessage, S2Role, PowerMeasurementValue, RmDetails } from './s2/messages';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateId = exports.makeResourceManagerDetails = exports.makeHandshake = exports.makeReceptionStatus = exports.serialize = exports.parse = exports.ReceptionStatusResult = exports.ControlType = exports.MessageType = exports.State = exports.S2Session = void 0;
|
|
4
|
+
var session_1 = require("./s2/session");
|
|
5
|
+
Object.defineProperty(exports, "S2Session", { enumerable: true, get: function () { return session_1.S2Session; } });
|
|
6
|
+
Object.defineProperty(exports, "State", { enumerable: true, get: function () { return session_1.State; } });
|
|
7
|
+
var messages_1 = require("./s2/messages");
|
|
8
|
+
Object.defineProperty(exports, "MessageType", { enumerable: true, get: function () { return messages_1.MessageType; } });
|
|
9
|
+
Object.defineProperty(exports, "ControlType", { enumerable: true, get: function () { return messages_1.ControlType; } });
|
|
10
|
+
Object.defineProperty(exports, "ReceptionStatusResult", { enumerable: true, get: function () { return messages_1.ReceptionStatusResult; } });
|
|
11
|
+
Object.defineProperty(exports, "parse", { enumerable: true, get: function () { return messages_1.parse; } });
|
|
12
|
+
Object.defineProperty(exports, "serialize", { enumerable: true, get: function () { return messages_1.serialize; } });
|
|
13
|
+
Object.defineProperty(exports, "makeReceptionStatus", { enumerable: true, get: function () { return messages_1.makeReceptionStatus; } });
|
|
14
|
+
Object.defineProperty(exports, "makeHandshake", { enumerable: true, get: function () { return messages_1.makeHandshake; } });
|
|
15
|
+
Object.defineProperty(exports, "makeResourceManagerDetails", { enumerable: true, get: function () { return messages_1.makeResourceManagerDetails; } });
|
|
16
|
+
Object.defineProperty(exports, "generateId", { enumerable: true, get: function () { return messages_1.generateId; } });
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":";;;AAAA,wCAA+C;AAAtC,oGAAA,SAAS,OAAA;AAAE,gGAAA,KAAK,OAAA;AAGzB,0CAUsB;AATpB,uGAAA,WAAW,OAAA;AACX,uGAAA,WAAW,OAAA;AACX,iHAAA,qBAAqB,OAAA;AACrB,iGAAA,KAAK,OAAA;AACL,qGAAA,SAAS,OAAA;AACT,+GAAA,mBAAmB,OAAA;AACnB,yGAAA,aAAa,OAAA;AACb,sHAAA,0BAA0B,OAAA;AAC1B,sGAAA,UAAU,OAAA"}
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S2 protocol message type constants (EN 50491-12-2).
|
|
3
|
+
* These are the message_type values used in S2 JSON messages.
|
|
4
|
+
*/
|
|
5
|
+
export declare const MessageType: Readonly<{
|
|
6
|
+
readonly HANDSHAKE: "Handshake";
|
|
7
|
+
readonly HANDSHAKE_RESPONSE: "HandshakeResponse";
|
|
8
|
+
readonly SESSION_REQUEST: "SessionRequest";
|
|
9
|
+
readonly RESOURCE_MANAGER_DETAILS: "ResourceManagerDetails";
|
|
10
|
+
readonly POWER_MEASUREMENT: "PowerMeasurement";
|
|
11
|
+
readonly RECEPTION_STATUS: "ReceptionStatus";
|
|
12
|
+
readonly REVOKE_OBJECT: "RevokeObject";
|
|
13
|
+
readonly SELECT_CONTROL_TYPE: "SelectControlType";
|
|
14
|
+
readonly INSTRUCTION: "Instruction";
|
|
15
|
+
readonly FRBC_ACTUATOR_STATUS: "FRBC.ActuatorStatus";
|
|
16
|
+
readonly FRBC_FILL_LEVEL_TARGET_PROFILE: "FRBC.FillLevelTargetProfile";
|
|
17
|
+
readonly FRBC_LEAKAGE_BEHAVIOUR: "FRBC.LeakagebBehaviour";
|
|
18
|
+
readonly FRBC_STORAGE_STATUS: "FRBC.StorageStatus";
|
|
19
|
+
readonly FRBC_SYSTEM_DESCRIPTION: "FRBC.SystemDescription";
|
|
20
|
+
readonly FRBC_TIMER_STATUS: "FRBC.TimerStatus";
|
|
21
|
+
readonly FRBC_USAGE_FORECAST: "FRBC.UsageForecast";
|
|
22
|
+
readonly FRBC_INSTRUCTION: "FRBC.Instruction";
|
|
23
|
+
readonly DDBC_ACTUAL_POWER: "DDBC.ActualPower";
|
|
24
|
+
readonly DDBC_AVERAGE_DEMAND_RATE_FORECAST: "DDBC.AverageDemandRateForecast";
|
|
25
|
+
readonly DDBC_SYSTEM_DESCRIPTION: "DDBC.SystemDescription";
|
|
26
|
+
readonly DDBC_TIMER_STATUS: "DDBC.TimerStatus";
|
|
27
|
+
readonly DDBC_INSTRUCTION: "DDBC.Instruction";
|
|
28
|
+
readonly PPBC_POWER_PROFILE_STATUS: "PPBC.PowerProfileStatus";
|
|
29
|
+
readonly PPBC_SCHEDULE_INSTRUCTION: "PPBC.ScheduleInstruction";
|
|
30
|
+
readonly PPBC_START_INTERRUPTION_INSTRUCTION: "PPBC.StartInterruptionInstruction";
|
|
31
|
+
readonly PPBC_END_INTERRUPTION_INSTRUCTION: "PPBC.EndInterruptionInstruction";
|
|
32
|
+
readonly PPBC_POWER_PROFILE: "PPBC.PowerProfileDefinition";
|
|
33
|
+
readonly OMBC_SYSTEM_DESCRIPTION: "OMBC.SystemDescription";
|
|
34
|
+
readonly OMBC_STATUS: "OMBC.Status";
|
|
35
|
+
readonly OMBC_INSTRUCTION: "OMBC.Instruction";
|
|
36
|
+
readonly PEBC_POWER_CONSTRAINTS: "PEBC.PowerConstraints";
|
|
37
|
+
readonly PEBC_DEVICE_CONSTRAINTS: "PEBC.DeviceConstraints";
|
|
38
|
+
readonly PEBC_ENERGY_CONSTRAINT: "PEBC.EnergyConstraint";
|
|
39
|
+
readonly PEBC_INSTRUCTION: "PEBC.Instruction";
|
|
40
|
+
readonly POWER_FORECAST: "PowerForecast";
|
|
41
|
+
readonly INSTRUCTION_STATUS_UPDATE: "InstructionStatusUpdate";
|
|
42
|
+
}>;
|
|
43
|
+
export type MessageTypeValue = (typeof MessageType)[keyof typeof MessageType];
|
|
44
|
+
/**
|
|
45
|
+
* S2 control type identifiers (full names as used in s2python / s2-ws-json).
|
|
46
|
+
*/
|
|
47
|
+
export declare const ControlType: Readonly<{
|
|
48
|
+
readonly NOT_CONTROLABLE: "NOT_CONTROLABLE";
|
|
49
|
+
readonly OMBC: "OPERATION_MODE_BASED_CONTROL";
|
|
50
|
+
readonly FRBC: "FILL_RATE_BASED_CONTROL";
|
|
51
|
+
readonly DDBC: "DEMAND_DRIVEN_BASED_CONTROL";
|
|
52
|
+
readonly PPBC: "POWER_PROFILE_BASED_CONTROL";
|
|
53
|
+
readonly PEBC: "POWER_ENVELOPE_BASED_CONTROL";
|
|
54
|
+
readonly NO_SELECTION: "NO_SELECTION";
|
|
55
|
+
}>;
|
|
56
|
+
export type ControlTypeValue = (typeof ControlType)[keyof typeof ControlType];
|
|
57
|
+
/**
|
|
58
|
+
* ReceptionStatus result values (matches s2python ReceptionStatusValues).
|
|
59
|
+
*/
|
|
60
|
+
/**
|
|
61
|
+
* Standard European grid connection types with their max power capacity at 230V nominal.
|
|
62
|
+
* Used to set PEBC power constraint outer limits (bidirectional: [-maxWatts, +maxWatts]).
|
|
63
|
+
*/
|
|
64
|
+
export declare const GRID_CONNECTIONS: Readonly<{
|
|
65
|
+
readonly '1x16A': {
|
|
66
|
+
readonly phases: 1;
|
|
67
|
+
readonly ampsPerPhase: 16;
|
|
68
|
+
readonly maxWatts: 3680;
|
|
69
|
+
};
|
|
70
|
+
readonly '3x16A': {
|
|
71
|
+
readonly phases: 3;
|
|
72
|
+
readonly ampsPerPhase: 16;
|
|
73
|
+
readonly maxWatts: 11040;
|
|
74
|
+
};
|
|
75
|
+
readonly '3x25A': {
|
|
76
|
+
readonly phases: 3;
|
|
77
|
+
readonly ampsPerPhase: 25;
|
|
78
|
+
readonly maxWatts: 17250;
|
|
79
|
+
};
|
|
80
|
+
readonly '3x32A': {
|
|
81
|
+
readonly phases: 3;
|
|
82
|
+
readonly ampsPerPhase: 32;
|
|
83
|
+
readonly maxWatts: 22080;
|
|
84
|
+
};
|
|
85
|
+
readonly '3x40A': {
|
|
86
|
+
readonly phases: 3;
|
|
87
|
+
readonly ampsPerPhase: 40;
|
|
88
|
+
readonly maxWatts: 27600;
|
|
89
|
+
};
|
|
90
|
+
readonly '3x63A': {
|
|
91
|
+
readonly phases: 3;
|
|
92
|
+
readonly ampsPerPhase: 63;
|
|
93
|
+
readonly maxWatts: 43470;
|
|
94
|
+
};
|
|
95
|
+
}>;
|
|
96
|
+
export type GridConnectionKey = keyof typeof GRID_CONNECTIONS;
|
|
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
|
+
export declare function gridConnectionToWatts(gridConnection: string | undefined, customMaxPowerW?: number): number | null;
|
|
103
|
+
export declare const ReceptionStatusResult: Readonly<{
|
|
104
|
+
readonly OK: "OK";
|
|
105
|
+
readonly INVALID_DATA: "INVALID_DATA";
|
|
106
|
+
readonly INVALID_MESSAGE: "INVALID_MESSAGE";
|
|
107
|
+
readonly INVALID_CONTENT: "INVALID_CONTENT";
|
|
108
|
+
readonly TEMPORARY_ERROR: "TEMPORARY_ERROR";
|
|
109
|
+
readonly PERMANENT_ERROR: "PERMANENT_ERROR";
|
|
110
|
+
}>;
|
|
111
|
+
export type ReceptionStatusResultValue = (typeof ReceptionStatusResult)[keyof typeof ReceptionStatusResult];
|
|
112
|
+
export declare const InstructionStatus: Readonly<{
|
|
113
|
+
readonly NEW: "NEW";
|
|
114
|
+
readonly ACCEPTED: "ACCEPTED";
|
|
115
|
+
readonly REJECTED: "REJECTED";
|
|
116
|
+
readonly REVOKED: "REVOKED";
|
|
117
|
+
readonly STARTED: "STARTED";
|
|
118
|
+
readonly SUCCEEDED: "SUCCEEDED";
|
|
119
|
+
readonly ABORTED: "ABORTED";
|
|
120
|
+
}>;
|
|
121
|
+
export type InstructionStatusValue = (typeof InstructionStatus)[keyof typeof InstructionStatus];
|
|
122
|
+
export declare const RevokableObjects: Readonly<{
|
|
123
|
+
readonly DDBC_AVERAGE_DEMAND_RATE_FORECAST: "DDBC.AverageDemandRateForecast";
|
|
124
|
+
readonly DDBC_INSTRUCTION: "DDBC.Instruction";
|
|
125
|
+
readonly DDBC_SYSTEM_DESCRIPTION: "DDBC.SystemDescription";
|
|
126
|
+
readonly FRBC_FILL_LEVEL_TARGET_PROFILE: "FRBC.FillLevelTargetProfile";
|
|
127
|
+
readonly FRBC_INSTRUCTION: "FRBC.Instruction";
|
|
128
|
+
readonly FRBC_LEAKAGE_BEHAVIOUR: "FRBC.LeakageBehaviour";
|
|
129
|
+
readonly FRBC_SYSTEM_DESCRIPTION: "FRBC.SystemDescription";
|
|
130
|
+
readonly FRBC_USAGE_FORECAST: "FRBC.UsageForecast";
|
|
131
|
+
readonly OMBC_INSTRUCTION: "OMBC.Instruction";
|
|
132
|
+
readonly OMBC_SYSTEM_DESCRIPTION: "OMBC.SystemDescription";
|
|
133
|
+
readonly PEBC_ENERGY_CONSTRAINT: "PEBC.EnergyConstraint";
|
|
134
|
+
readonly PEBC_INSTRUCTION: "PEBC.Instruction";
|
|
135
|
+
readonly PEBC_POWER_CONSTRAINTS: "PEBC.PowerConstraints";
|
|
136
|
+
readonly PPBC_END_INTERRUPTION_INSTRUCTION: "PPBC.EndInterruptionInstruction";
|
|
137
|
+
readonly PPBC_POWER_PROFILE_DEFINITION: "PPBC.PowerProfileDefinition";
|
|
138
|
+
readonly PPBC_SCHEDULE_INSTRUCTION: "PPBC.ScheduleInstruction";
|
|
139
|
+
readonly PPBC_START_INTERRUPTION_INSTRUCTION: "PPBC.StartInterruptionInstruction";
|
|
140
|
+
}>;
|
|
141
|
+
export type RevokableObjectsValue = (typeof RevokableObjects)[keyof typeof RevokableObjects];
|
|
142
|
+
/** Base shape for any S2 message parsed from JSON. */
|
|
143
|
+
export interface S2IncomingMessage {
|
|
144
|
+
message_type: string;
|
|
145
|
+
message_id?: string;
|
|
146
|
+
[key: string]: unknown;
|
|
147
|
+
}
|
|
148
|
+
export interface S2Role {
|
|
149
|
+
role: string;
|
|
150
|
+
commodity: string;
|
|
151
|
+
}
|
|
152
|
+
export interface PowerMeasurementValue {
|
|
153
|
+
commodity_quantity: string;
|
|
154
|
+
value: number;
|
|
155
|
+
}
|
|
156
|
+
export interface S2HandshakeMessage {
|
|
157
|
+
message_type: typeof MessageType.HANDSHAKE;
|
|
158
|
+
message_id: string;
|
|
159
|
+
role: 'RM';
|
|
160
|
+
supported_protocol_versions: string[];
|
|
161
|
+
}
|
|
162
|
+
export interface S2ReceptionStatusMessage {
|
|
163
|
+
message_type: typeof MessageType.RECEPTION_STATUS;
|
|
164
|
+
subject_message_id: string;
|
|
165
|
+
status: ReceptionStatusResultValue;
|
|
166
|
+
diagnostic_label?: string;
|
|
167
|
+
}
|
|
168
|
+
export interface S2RevokeObjectMessage {
|
|
169
|
+
message_type: typeof MessageType.REVOKE_OBJECT;
|
|
170
|
+
message_id: string;
|
|
171
|
+
object_id: string;
|
|
172
|
+
object_type: RevokableObjectsValue;
|
|
173
|
+
}
|
|
174
|
+
export interface InstructionStatusUpdateMessage {
|
|
175
|
+
message_type: typeof MessageType.INSTRUCTION_STATUS_UPDATE;
|
|
176
|
+
message_id: string;
|
|
177
|
+
instruction_id: string;
|
|
178
|
+
status_type: InstructionStatusValue;
|
|
179
|
+
timestamp: string;
|
|
180
|
+
}
|
|
181
|
+
export interface S2ResourceManagerDetailsMessage {
|
|
182
|
+
message_type: typeof MessageType.RESOURCE_MANAGER_DETAILS;
|
|
183
|
+
message_id: string;
|
|
184
|
+
resource_id: string;
|
|
185
|
+
name: string;
|
|
186
|
+
roles: S2Role[];
|
|
187
|
+
manufacturer: string;
|
|
188
|
+
model: string;
|
|
189
|
+
serial_number: string;
|
|
190
|
+
firmware_version: string;
|
|
191
|
+
available_control_types: string[];
|
|
192
|
+
provides_forecast: boolean;
|
|
193
|
+
provides_power_measurement_types: string[];
|
|
194
|
+
instruction_processing_delay: number;
|
|
195
|
+
}
|
|
196
|
+
export interface S2OMBCSystemDescriptionMessage {
|
|
197
|
+
message_type: typeof MessageType.OMBC_SYSTEM_DESCRIPTION;
|
|
198
|
+
message_id: string;
|
|
199
|
+
valid_from: string;
|
|
200
|
+
operation_modes: unknown[];
|
|
201
|
+
transitions: unknown[];
|
|
202
|
+
timers: unknown[];
|
|
203
|
+
}
|
|
204
|
+
export interface S2OMBCStatusMessage {
|
|
205
|
+
message_type: typeof MessageType.OMBC_STATUS;
|
|
206
|
+
message_id: string;
|
|
207
|
+
active_operation_mode_id: string;
|
|
208
|
+
operation_mode_factor: number;
|
|
209
|
+
previous_operation_mode_id?: string;
|
|
210
|
+
transition_timestamp?: string;
|
|
211
|
+
}
|
|
212
|
+
export interface S2PowerMeasurementMessage {
|
|
213
|
+
message_type: typeof MessageType.POWER_MEASUREMENT;
|
|
214
|
+
message_id: string;
|
|
215
|
+
measurement_timestamp: string;
|
|
216
|
+
values: PowerMeasurementValue[];
|
|
217
|
+
}
|
|
218
|
+
export interface RmDetails {
|
|
219
|
+
resourceId: string;
|
|
220
|
+
name: string;
|
|
221
|
+
roles: S2Role[];
|
|
222
|
+
availableControlTypes: string[];
|
|
223
|
+
providesForecast: boolean;
|
|
224
|
+
providesPowerMeasurementTypes?: string[];
|
|
225
|
+
instructionProcessingDelay?: number;
|
|
226
|
+
manufacturer?: string;
|
|
227
|
+
model?: string;
|
|
228
|
+
serialNumber?: string;
|
|
229
|
+
firmwareVersion?: string;
|
|
230
|
+
}
|
|
231
|
+
export interface OMBCSystemDescriptionConfig {
|
|
232
|
+
operationModes: unknown[];
|
|
233
|
+
transitions?: unknown[];
|
|
234
|
+
timers?: unknown[];
|
|
235
|
+
}
|
|
236
|
+
export interface OMBCStatusConfig {
|
|
237
|
+
activeOperationModeId: string;
|
|
238
|
+
operationModeFactor?: number;
|
|
239
|
+
previousOperationModeId?: string;
|
|
240
|
+
transitionTimestamp?: string;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Simplified input for building a PEBC.PowerConstraints message.
|
|
244
|
+
* Produces a single commodity constraint with matching LOWER_LIMIT and
|
|
245
|
+
* UPPER_LIMIT ranges, consequence_type DEFER - as required by most CEMs.
|
|
246
|
+
*/
|
|
247
|
+
export interface PEBCPowerConstraintsInput {
|
|
248
|
+
/** e.g. 'ELECTRIC.POWER.3_PHASE_SYMMETRIC' */
|
|
249
|
+
commodityQuantity: string;
|
|
250
|
+
/** Lower bound of the allowed power range in Watts (may be negative for export) */
|
|
251
|
+
minPower: number;
|
|
252
|
+
/** Upper bound of the allowed power range in Watts */
|
|
253
|
+
maxPower: number;
|
|
254
|
+
/** ISO 8601 datetime; defaults to now */
|
|
255
|
+
validFrom?: string;
|
|
256
|
+
}
|
|
257
|
+
export interface PowerForecastValue {
|
|
258
|
+
commodity_quantity: string;
|
|
259
|
+
value_expected: number;
|
|
260
|
+
value_upper_limit?: number;
|
|
261
|
+
value_lower_limit?: number;
|
|
262
|
+
}
|
|
263
|
+
export interface PowerForecastElement {
|
|
264
|
+
duration: number;
|
|
265
|
+
power_values: PowerForecastValue[];
|
|
266
|
+
}
|
|
267
|
+
export interface PowerForecastInput {
|
|
268
|
+
startTime: string;
|
|
269
|
+
elements: PowerForecastElement[];
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Parse a raw WebSocket message string into an S2 message object.
|
|
273
|
+
* Returns null and calls onError if parsing fails.
|
|
274
|
+
*
|
|
275
|
+
* @param raw - raw JSON string
|
|
276
|
+
* @param onError - called with an Error if parsing fails
|
|
277
|
+
*/
|
|
278
|
+
export declare function parse(raw: string, onError: (err: Error) => void): S2IncomingMessage | null;
|
|
279
|
+
/**
|
|
280
|
+
* Serialize an S2 message object to a string for sending over the wire.
|
|
281
|
+
*/
|
|
282
|
+
export declare function serialize(msg: object): string;
|
|
283
|
+
/**
|
|
284
|
+
* Create a ReceptionStatus message acknowledging a received message.
|
|
285
|
+
*
|
|
286
|
+
* @param subjectMessageId - message_id of the message being acknowledged
|
|
287
|
+
* @param status - one of ReceptionStatusResult values
|
|
288
|
+
* @param diagnosticLabel - optional human-readable diagnostic
|
|
289
|
+
*/
|
|
290
|
+
export declare function makeReceptionStatus(subjectMessageId: string, status: ReceptionStatusResultValue, diagnosticLabel?: string): S2ReceptionStatusMessage;
|
|
291
|
+
/**
|
|
292
|
+
* Create a Handshake message (sent by RM on connect).
|
|
293
|
+
*
|
|
294
|
+
* @param rmId - unique ID identifying this Resource Manager
|
|
295
|
+
*/
|
|
296
|
+
export declare function makeHandshake(rmId: string): S2HandshakeMessage;
|
|
297
|
+
/**
|
|
298
|
+
* Create a ResourceManagerDetails message (sent by RM after HandshakeResponse).
|
|
299
|
+
*/
|
|
300
|
+
export declare function makeResourceManagerDetails(details: RmDetails): S2ResourceManagerDetailsMessage;
|
|
301
|
+
/**
|
|
302
|
+
* Create an OMBC.SystemDescription message.
|
|
303
|
+
*/
|
|
304
|
+
export declare function makeOMBCSystemDescription(config: OMBCSystemDescriptionConfig): S2OMBCSystemDescriptionMessage;
|
|
305
|
+
/**
|
|
306
|
+
* Create an OMBC.Status message.
|
|
307
|
+
*/
|
|
308
|
+
export declare function makeOMBCStatus(status: OMBCStatusConfig): S2OMBCStatusMessage;
|
|
309
|
+
/**
|
|
310
|
+
* Create a PowerMeasurement message (sent by RM to report current power).
|
|
311
|
+
*
|
|
312
|
+
* @param values - array of { commodity_quantity, value } objects
|
|
313
|
+
*/
|
|
314
|
+
export declare function makePowerMeasurement(values: PowerMeasurementValue[]): S2PowerMeasurementMessage;
|
|
315
|
+
/**
|
|
316
|
+
* Build a PEBC.PowerConstraints message with matching LOWER_LIMIT and
|
|
317
|
+
* UPPER_LIMIT ranges and consequence_type DEFER.
|
|
318
|
+
*
|
|
319
|
+
* Wire format (s2-ws-json 0.0.2-beta):
|
|
320
|
+
* id + allowed_limit_ranges are top-level fields on the message itself,
|
|
321
|
+
* not nested under a power_constraints array.
|
|
322
|
+
*/
|
|
323
|
+
export declare function makePEBCPowerConstraints(input: PEBCPowerConstraintsInput): object;
|
|
324
|
+
/**
|
|
325
|
+
* Build a PowerForecast message from pre-formed elements.
|
|
326
|
+
*
|
|
327
|
+
* @param input.startTime - ISO 8601 timezone-aware datetime for the first element
|
|
328
|
+
* @param input.elements - array of { duration (ms), power_values: [{ commodity_quantity, value_expected }] }
|
|
329
|
+
*/
|
|
330
|
+
export declare function makePowerForecast(input: PowerForecastInput): object;
|
|
331
|
+
/**
|
|
332
|
+
* Create an InstructionStatusUpdate message reporting the current lifecycle state of an instruction.
|
|
333
|
+
*
|
|
334
|
+
* @param instructionId - the `id` field of the instruction (not its message_id)
|
|
335
|
+
* @param status - one of InstructionStatus values
|
|
336
|
+
*/
|
|
337
|
+
export declare function makeInstructionStatusUpdate(instructionId: string, status: InstructionStatusValue): InstructionStatusUpdateMessage;
|
|
338
|
+
/**
|
|
339
|
+
* Generate a UUID v4 message ID.
|
|
340
|
+
* Node >=14.17.4 is required, which includes crypto.randomUUID.
|
|
341
|
+
*/
|
|
342
|
+
export declare function generateId(): string;
|