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.
Files changed (40) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/LICENSE +21 -0
  3. package/README.md +119 -0
  4. package/dist/lib/index.d.ts +4 -0
  5. package/dist/lib/index.js +17 -0
  6. package/dist/lib/index.js.map +1 -0
  7. package/dist/lib/s2/messages.d.ts +342 -0
  8. package/dist/lib/s2/messages.js +330 -0
  9. package/dist/lib/s2/messages.js.map +1 -0
  10. package/dist/lib/s2/schedule.d.ts +35 -0
  11. package/dist/lib/s2/schedule.js +109 -0
  12. package/dist/lib/s2/schedule.js.map +1 -0
  13. package/dist/lib/s2/session.d.ts +138 -0
  14. package/dist/lib/s2/session.js +304 -0
  15. package/dist/lib/s2/session.js.map +1 -0
  16. package/dist/lib/transport/websocket.d.ts +58 -0
  17. package/dist/lib/transport/websocket.js +149 -0
  18. package/dist/lib/transport/websocket.js.map +1 -0
  19. package/dist/nodes/s2-cem-config/index.d.ts +3 -0
  20. package/dist/nodes/s2-cem-config/index.html +54 -0
  21. package/dist/nodes/s2-cem-config/index.js +16 -0
  22. package/dist/nodes/s2-cem-config/index.js.map +1 -0
  23. package/dist/nodes/s2-rm/icons/s2-logo.svg +14 -0
  24. package/dist/nodes/s2-rm/index.d.ts +34 -0
  25. package/dist/nodes/s2-rm/index.html +167 -0
  26. package/dist/nodes/s2-rm/index.js +655 -0
  27. package/dist/nodes/s2-rm/index.js.map +1 -0
  28. package/dist/nodes/s2-rm-config/index.d.ts +3 -0
  29. package/dist/nodes/s2-rm-config/index.html +254 -0
  30. package/dist/nodes/s2-rm-config/index.js +20 -0
  31. package/dist/nodes/s2-rm-config/index.js.map +1 -0
  32. package/dist/nodes/s2-websocket/icons/s2-logo.svg +14 -0
  33. package/dist/nodes/s2-websocket/index.d.ts +22 -0
  34. package/dist/nodes/s2-websocket/index.html +83 -0
  35. package/dist/nodes/s2-websocket/index.js +127 -0
  36. package/dist/nodes/s2-websocket/index.js.map +1 -0
  37. package/dist/types/config-nodes.d.ts +39 -0
  38. package/dist/types/config-nodes.js +3 -0
  39. package/dist/types/config-nodes.js.map +1 -0
  40. package/package.json +84 -0
@@ -0,0 +1,34 @@
1
+ import { NodeRedApp } from '../../types/node-red';
2
+ /**
3
+ * s2-rm node (S2 Resource Manager)
4
+ *
5
+ * Manages S2 protocol sessions for all connected CEMs. Sits between
6
+ * the transport node (victron-virtual acload, s2-websocket, etc.) and the
7
+ * rest of the flow.
8
+ *
9
+ * Wiring:
10
+ * [transport port 2] -> [s2-rm input]
11
+ * [s2-rm port 1] -> [transport input]
12
+ *
13
+ * Input msg.payload from transport:
14
+ * { command: 'Connect', cemId, keepAliveInterval }
15
+ * { command: 'Message', cemId, message } <- message is a raw S2 JSON string
16
+ * { command: 'KeepAlive', cemId }
17
+ * { command: 'PowerMeasurement', cemId, values }
18
+ * { command: 'Disconnect', cemId }
19
+ *
20
+ * Output port 1 - messages to send to the CEM (via transport input):
21
+ * { payload: { s2Signal: 'Message', message: <S2 message object> }, cemId }
22
+ * { payload: { s2Signal: 'PowerMeasurementStart', commodityQuantities: [...] }, cemId }
23
+ *
24
+ * Output port 2 - S2 messages received from CEM, forwarded for downstream processing:
25
+ * { payload: <S2 message object>, cemId: <string>, topic: <message_type string> }
26
+ * Also emits lifecycle events (route via Switch node on msg.topic):
27
+ * { topic: 'Connected', cemId: <string> }
28
+ * { topic: 'Disconnected', cemId: <string>, reason: 'cem_initiated' | 'keepalive_timeout' }
29
+ *
30
+ * Output port 3 - S2 instructions from CEM:
31
+ * { payload: <S2 instruction object>, cemId: <string> }
32
+ */
33
+ declare const _default: (RED: NodeRedApp) => void;
34
+ export = _default;
@@ -0,0 +1,167 @@
1
+ <script src="resources/node-red-contrib-s2/s2-common.js"></script>
2
+ <script type="text/javascript">
3
+ RED.nodes.registerType('s2-rm', {
4
+ category: 's2',
5
+ color: '#5A8EC2',
6
+ defaults: {
7
+ name: { value: '' },
8
+ rmConfig: { value: '', type: 's2-rm-config', required: true },
9
+ cem: { value: '', type: 's2-cem-config', required: false },
10
+ controlTypeConfig: { value: '' },
11
+ providesPowerMeasurement: { value: '3_PHASE_SYMMETRIC' },
12
+ providesForecast: { value: false }
13
+ },
14
+ inputs: 1,
15
+ outputs: 4,
16
+ icon: 's2-logo.svg',
17
+ outputLabels: ['to transport', 'from CEM', 'instructions', 'schedule'],
18
+ inputLabels: ['from transport'],
19
+ label: function () {
20
+ return this.name || 'S2 Resource Manager'
21
+ },
22
+ labelStyle: function () {
23
+ return this.name ? 'node_label_italic' : ''
24
+ },
25
+ oneditprepare: function () {
26
+ // Migrate legacy boolean to string value
27
+ if (this.providesPowerMeasurement === true) {
28
+ this.providesPowerMeasurement = '3_PHASE_SYMMETRIC'
29
+ $('#node-input-providesPowerMeasurement').val('3_PHASE_SYMMETRIC')
30
+ } else if (this.providesPowerMeasurement === false) {
31
+ this.providesPowerMeasurement = ''
32
+ $('#node-input-providesPowerMeasurement').val('')
33
+ }
34
+
35
+ $('#node-input-controlTypeConfig').typedInput({ types: ['json'] })
36
+
37
+ window.__s2Common.initializeTooltips()
38
+
39
+ if (!this.controlTypeConfig) {
40
+ var modeId = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
41
+ var r = Math.random() * 16 | 0
42
+ return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16)
43
+ })
44
+ var defaultConfig = {
45
+ OMBC: {
46
+ systemDescription: {
47
+ operationModes: [
48
+ {
49
+ id: modeId,
50
+ diagnostic_label: 'Normal operation',
51
+ power_ranges: [
52
+ {
53
+ commodity_quantity: 'ELECTRIC.POWER.3_PHASE_SYMMETRIC',
54
+ start_of_range: 0,
55
+ end_of_range: 2500
56
+ }
57
+ ],
58
+ abnormal_condition_only: false
59
+ }
60
+ ],
61
+ transitions: [],
62
+ timers: []
63
+ },
64
+ status: {
65
+ activeOperationModeId: modeId,
66
+ operationModeFactor: 1
67
+ }
68
+ }
69
+ }
70
+ $('#node-input-controlTypeConfig').typedInput('value', JSON.stringify(defaultConfig, null, 2))
71
+ }
72
+
73
+ }
74
+ })
75
+ </script>
76
+
77
+ <script type="text/html" data-template-name="s2-rm">
78
+ <div class="s2-form">
79
+
80
+ <div class="form-row">
81
+ <label for="node-input-name">
82
+ <i class="fa fa-tag"></i> Name
83
+ </label>
84
+ <input type="text" id="node-input-name" placeholder="Name (optional)">
85
+ </div>
86
+
87
+ <div class="form-row">
88
+ <label for="node-input-rmConfig"><i class="fa fa-id-card"></i> RM Config<i class="fa fa-info-circle tooltip-icon" data-tooltip="Resource Manager identity: UUID, name, control types, manufacturer. Shared with the transport node."></i></label>
89
+ <input type="text" id="node-input-rmConfig">
90
+ </div>
91
+
92
+ <div class="form-row">
93
+ <label for="node-input-cem"><i class="fa fa-globe"></i> CEM<i class="fa fa-info-circle tooltip-icon" data-tooltip="Optional. Link to the same s2-cem-config used by the transport node. When set, populates flow.cemFlexInstructionUrl and flow.cemApiAuth so function nodes can POST flex instructions to the CEM REST API without duplicating credentials."></i></label>
94
+ <input type="text" id="node-input-cem">
95
+ </div>
96
+
97
+ <div class="form-row">
98
+ <label for="node-input-controlTypeConfig"><i class="fa fa-code"></i> Control Type<i class="fa fa-info-circle tooltip-icon" data-tooltip="JSON configuration per control type. For OMBC: operation modes, power ranges, transitions and timers. Keys: OMBC.systemDescription.operationModes, OMBC.status.activeOperationModeId"></i></label>
99
+ <input type="text" id="node-input-controlTypeConfig">
100
+ </div>
101
+
102
+ <div class="form-row">
103
+ <label for="node-input-providesPowerMeasurement"><i class="fa fa-bolt"></i> Power Meas.<i class="fa fa-info-circle tooltip-icon" data-tooltip="Commodity quantities for power measurement. Advertised to the CEM in ResourceManagerDetails."></i></label>
104
+ <select id="node-input-providesPowerMeasurement" style="width: 70%;">
105
+ <option value="">None</option>
106
+ <option value="3_PHASE_SYMMETRIC">3-phase symmetric</option>
107
+ <option value="L1_L2_L3">Per phase (L1, L2, L3)</option>
108
+ </select>
109
+ </div>
110
+
111
+ <div class="form-row">
112
+ <label for="node-input-providesForecast">
113
+ <i class="fa fa-line-chart"></i> Forecast
114
+ </label>
115
+ <input type="checkbox" id="node-input-providesForecast" style="width: auto; margin-top: 6px;">
116
+ <span style="margin-left: 6px;">Provides power forecast</span>
117
+ </div>
118
+
119
+ </div>
120
+ </script>
121
+
122
+ <link rel="stylesheet" href="resources/node-red-contrib-s2/s2-styles.css">
123
+
124
+ <script type="text/html" data-help-name="s2-rm">
125
+ <p>Manages S2 protocol sessions for connected CEMs. Handles the S2 handshake, sends ResourceManagerDetails, and responds to SelectControlType.</p>
126
+ <p>RM identity (resource ID, name, control types) is configured in the linked <b>s2-rm-config</b> node, shared with the transport node.</p>
127
+ <h3>Input</h3>
128
+ <dl class="message-properties">
129
+ <dt>payload <span class="property-type">object</span></dt>
130
+ <dd>Command from transport: <code>{ command, cemId, ... }</code></dd>
131
+ </dl>
132
+ <h3>Outputs</h3>
133
+ <ol class="node-ports">
134
+ <li>To transport
135
+ <dl class="message-properties">
136
+ <dt>payload <span class="property-type">object</span></dt>
137
+ <dd>S2 signal for transport: <code>{ s2Signal: 'Message', message: ... }</code> or <code>{ s2Signal: 'PowerMeasurementStart', ... }</code></dd>
138
+ </dl>
139
+ </li>
140
+ <li>From CEM
141
+ <dl class="message-properties">
142
+ <dt>payload <span class="property-type">object</span></dt>
143
+ <dd>S2 messages received from the CEM (HandshakeResponse, SelectControlType, ReceptionStatus, etc.).</dd>
144
+ <dt>cemId <span class="property-type">string</span></dt>
145
+ <dd>ID of the CEM that sent the message.</dd>
146
+ </dl>
147
+ </li>
148
+ <li>Instructions
149
+ <dl class="message-properties">
150
+ <dt>payload <span class="property-type">object</span></dt>
151
+ <dd>Control instructions from the CEM (OMBC.Instruction, PEBC.Instruction, etc.).</dd>
152
+ <dt>cemId <span class="property-type">string</span></dt>
153
+ <dd>ID of the CEM that sent the instruction.</dd>
154
+ </dl>
155
+ </li>
156
+ <li>Schedule
157
+ <dl class="message-properties">
158
+ <dt>payload.commodityQuantity <span class="property-type">string</span></dt>
159
+ <dd>Commodity quantity for all elements (e.g. <code>ELECTRIC.POWER.3_PHASE_SYMMETRIC</code>).</dd>
160
+ <dt>payload.elements <span class="property-type">array</span></dt>
161
+ <dd>Full accumulated PEBC schedule as an array of <code>{ startTime, endTime, durationSec, lowerBound, upperBound }</code>. Emitted each time the schedule is updated. Use this to program DESS schedule slots or similar downstream consumers.</dd>
162
+ <dt>cemId <span class="property-type">string</span></dt>
163
+ <dd>ID of the CEM that issued the schedule.</dd>
164
+ </dl>
165
+ </li>
166
+ </ol>
167
+ </script>