@impact0815/node-red-contrib-alphaess-modbus 0.0.0-stage → 0.4.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/CHANGELOG.md +98 -0
- package/LICENSE +21 -0
- package/README.de.md +422 -0
- package/README.md +427 -2
- package/alphaess-modbus.html +256 -0
- package/alphaess-modbus.js +399 -0
- package/examples/alphaess-modbus-example.json +420 -0
- package/lib/commands.js +145 -0
- package/lib/context-store.js +30 -0
- package/lib/derived.js +163 -0
- package/lib/i18n.js +57 -0
- package/lib/modbus-tcp.js +204 -0
- package/lib/mqtt.js +80 -0
- package/lib/registers.js +434 -0
- package/locales/de/alphaess-modbus.html +317 -0
- package/locales/de/alphaess-modbus.json +106 -0
- package/locales/en-US/alphaess-modbus.html +315 -0
- package/locales/en-US/alphaess-modbus.json +106 -0
- package/package.json +54 -5
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
<script type="text/html" data-help-name="alphaess-modbus-config">
|
|
2
|
+
<p>Modbus TCP connection to an Alpha ESS system (EMS). Used by one or more <b>AlphaESS Modbus</b> nodes.</p>
|
|
3
|
+
|
|
4
|
+
<h3>Settings</h3>
|
|
5
|
+
<dl class="message-properties">
|
|
6
|
+
<dt>Host <span class="property-type">IP / hostname</span></dt>
|
|
7
|
+
<dd>Address of the EMS in your network. A fixed IP address (DHCP reservation in the router) is recommended.
|
|
8
|
+
The address the system currently uses is shown in <code>details.systemConfig.localIp</code>.</dd>
|
|
9
|
+
<dt>Port <span class="property-type">number</span></dt>
|
|
10
|
+
<dd>Modbus TCP port, normally <code>502</code>.</dd>
|
|
11
|
+
<dt>Unit ID <span class="property-type">number</span></dt>
|
|
12
|
+
<dd>Modbus slave address. Alpha ESS uses <code>85</code> (0x55) by default, visible in
|
|
13
|
+
<code>details.systemConfig.modbusAddress</code>.</dd>
|
|
14
|
+
<dt>Timeout <span class="property-type">ms</span></dt>
|
|
15
|
+
<dd>Maximum wait time per request (default 2000 ms). Increase to 3000–5000 ms for WLAN or powerline connections.
|
|
16
|
+
After a timeout the connection is closed and re-opened with the next request.</dd>
|
|
17
|
+
<dt>Delay <span class="property-type">ms</span></dt>
|
|
18
|
+
<dd>Pause between two requests (default 20 ms). Increase to 50–100 ms if the EMS reports timeouts
|
|
19
|
+
or <i>Slave device busy</i>.</dd>
|
|
20
|
+
</dl>
|
|
21
|
+
|
|
22
|
+
<h3>Details</h3>
|
|
23
|
+
<ul>
|
|
24
|
+
<li>All nodes that use this configuration share <b>one</b> TCP connection. Requests are sent one after another,
|
|
25
|
+
never in parallel.</li>
|
|
26
|
+
<li>The EMS usually accepts <b>only one Modbus TCP connection at a time</b>. Further connections are refused.</li>
|
|
27
|
+
<li>Modbus TCP must be enabled on the system. After firmware updates, check that it is still enabled.</li>
|
|
28
|
+
</ul>
|
|
29
|
+
|
|
30
|
+
<h3>Troubleshooting</h3>
|
|
31
|
+
<dl class="message-properties">
|
|
32
|
+
<dt><code>ECONNREFUSED</code></dt>
|
|
33
|
+
<dd>The system is reachable but refuses the connection. In almost all cases another Modbus client is still connected:
|
|
34
|
+
<ul>
|
|
35
|
+
<li>old <code>modbus-getter</code> / <code>modbus-write</code> nodes in other tabs (search with Ctrl+F for <code>modbus</code>),</li>
|
|
36
|
+
<li>an <b>unused</b> <code>modbus-client</code> config node of <i>node-red-contrib-modbus</i> – Node-RED starts config nodes
|
|
37
|
+
even if no node uses them. Delete it under <i>Configuration nodes</i> and deploy with <i>Full</i>,</li>
|
|
38
|
+
<li>other programs such as Home Assistant, ioBroker, evcc or a wallbox load management.</li>
|
|
39
|
+
</ul>
|
|
40
|
+
If nothing else is connected, check that Modbus TCP is enabled, or restart the EMS.</dd>
|
|
41
|
+
<dt><code>Timeout</code> / <code>Connect timeout</code></dt>
|
|
42
|
+
<dd>Wrong IP address, system not reachable (network, firewall, Docker network) or a slow connection.
|
|
43
|
+
Test from the Node-RED host: <code>nc -zv <ip> 502</code>.</dd>
|
|
44
|
+
<dt><code>Modbus exception 2 (Illegal data address)</code></dt>
|
|
45
|
+
<dd>The system does not support a register block. Disable that block in the node (e.g. <i>PV meter</i> on systems without PV meter).
|
|
46
|
+
Blocks that were extended in the newer register list fall back to the older length automatically.</dd>
|
|
47
|
+
</dl>
|
|
48
|
+
|
|
49
|
+
<h3>Disclaimer</h3>
|
|
50
|
+
<p>Independent community project, not affiliated with or endorsed by Alpha ESS. Provided "as is", without warranty of any kind –
|
|
51
|
+
see the <i>AlphaESS Modbus</i> node help and the LICENSE.</p>
|
|
52
|
+
</script>
|
|
53
|
+
|
|
54
|
+
<script type="text/html" data-help-name="alphaess-modbus">
|
|
55
|
+
<p>Reads realtime data from an Alpha ESS storage system (SMILE, Storion) locally via Modbus TCP, calculates house consumption,
|
|
56
|
+
autarky, daily energy and alarms, and optionally publishes everything to MQTT.
|
|
57
|
+
Control commands (dispatch, feed-in limit, time periods) are available but <b>disabled by default</b>.</p>
|
|
58
|
+
|
|
59
|
+
<h3>Quick start</h3>
|
|
60
|
+
<ol>
|
|
61
|
+
<li>Create a connection with the IP address of the system (port 502, unit ID 85).</li>
|
|
62
|
+
<li>Keep the default blocks and the interval of 15 s. Connect a debug node to output 1.</li>
|
|
63
|
+
<li>Deploy. After a few seconds the status shows <code>PV … | Grid … | SOC … | Load …</code>.</li>
|
|
64
|
+
<li>Optional: set up a persistent context store for the daily values and select an MQTT broker.</li>
|
|
65
|
+
</ol>
|
|
66
|
+
<p>If the status stays red with <code>ECONNREFUSED</code>, another Modbus client is still connected – see the help of the connection node.</p>
|
|
67
|
+
|
|
68
|
+
<h3>Inputs</h3>
|
|
69
|
+
<p>The command is selected with <code>msg.topic</code>. Without a topic the node reads all blocks.</p>
|
|
70
|
+
<dl class="message-properties">
|
|
71
|
+
<dt>topic <span class="property-type">string</span></dt>
|
|
72
|
+
<dd>One of the commands below.</dd>
|
|
73
|
+
<dt class="optional">payload <span class="property-type">number | object</span></dt>
|
|
74
|
+
<dd>Parameters of the command.</dd>
|
|
75
|
+
</dl>
|
|
76
|
+
|
|
77
|
+
<h4>Read commands</h4>
|
|
78
|
+
<dl class="message-properties">
|
|
79
|
+
<dt><code>read</code> (or no topic)</dt>
|
|
80
|
+
<dd>Reads all enabled blocks now, including the slow blocks. Result on output 1. Useful with interval <code>0</code>
|
|
81
|
+
to control polling with your own inject node.</dd>
|
|
82
|
+
<dt><code>readInfo</code></dt>
|
|
83
|
+
<dd>Reads serial numbers and firmware versions again. Result on output 3.</dd>
|
|
84
|
+
<dt><code>readRaw</code></dt>
|
|
85
|
+
<dd>Reads raw holding registers, e.g. to check a value against the register documentation. Result on output 3.
|
|
86
|
+
<pre>{ "topic": "readRaw", "payload": { "address": 2128, "count": 1 } }</pre>
|
|
87
|
+
<code>address</code> is decimal (or <code>0x0850</code> in a JSON expression), <code>count</code> 1–125.</dd>
|
|
88
|
+
</dl>
|
|
89
|
+
|
|
90
|
+
<h4>Write commands</h4>
|
|
91
|
+
<p>Require <b>Allow write access</b>. Result on output 3. Errors (invalid values, write protection, min. interval)
|
|
92
|
+
are node errors and can be handled with a <i>catch</i> node. Read the <i>Disclaimer</i> below before using them.</p>
|
|
93
|
+
<dl class="message-properties">
|
|
94
|
+
<dt><code>timePeriod</code></dt>
|
|
95
|
+
<dd>Changes the charge/discharge time periods and SOC limits. <b>Only the given fields are changed</b>, everything else stays as it is.
|
|
96
|
+
<pre>{ "topic": "timePeriod", "payload": { "upsReserveSoc": 20 } }</pre>
|
|
97
|
+
<pre>{
|
|
98
|
+
"topic": "timePeriod",
|
|
99
|
+
"payload": {
|
|
100
|
+
"flag": 1,
|
|
101
|
+
"chargeCutSoc": 90,
|
|
102
|
+
"charge1": { "start": "01:00", "stop": "05:00" }
|
|
103
|
+
}
|
|
104
|
+
}</pre>
|
|
105
|
+
<ul>
|
|
106
|
+
<li><code>flag</code>: 0 = off, 1 = charge periods active, 2 = discharge periods active, 3 = both</li>
|
|
107
|
+
<li><code>upsReserveSoc</code>: SOC in % that is kept as reserve (the battery is not discharged below it)</li>
|
|
108
|
+
<li><code>chargeCutSoc</code>: SOC in % up to which the battery is charged from the grid in a charge period</li>
|
|
109
|
+
<li><code>charge1</code>, <code>charge2</code>, <code>discharge1</code>, <code>discharge2</code>:
|
|
110
|
+
<code>{ "start": "HH:MM", "stop": "HH:MM" }</code>, start or stop alone is possible</li>
|
|
111
|
+
</ul>
|
|
112
|
+
Lowering <code>upsReserveSoc</code> takes effect immediately: the battery may discharge down to the new value right away.
|
|
113
|
+
If that should only happen at a certain time, send the command at that time.</dd>
|
|
114
|
+
<dt><code>feedIn</code></dt>
|
|
115
|
+
<dd>Maximum feed-in into the grid in %. A feed-in limit may be required by your grid operator – only change it if you are allowed to.
|
|
116
|
+
<pre>{ "topic": "feedIn", "payload": 70 }</pre>
|
|
117
|
+
<code>{ "percent": 70 }</code> is also accepted.</dd>
|
|
118
|
+
<dt><code>dispatch</code></dt>
|
|
119
|
+
<dd>Forces the battery to charge or discharge for a limited time.
|
|
120
|
+
<pre>{ "topic": "dispatch", "payload": { "power": -3000, "soc": 90, "duration": 900 } }</pre>
|
|
121
|
+
<ul>
|
|
122
|
+
<li><code>power</code> in W: <b>negative = charge</b>, positive = discharge (same sign as <code>payload.battery</code>)</li>
|
|
123
|
+
<li><code>soc</code>: target SOC in %, default 100 when charging, 10 when discharging</li>
|
|
124
|
+
<li><code>duration</code> in s, default 300 – after this time the system returns to normal operation by itself.
|
|
125
|
+
Keep it short and repeat the command if needed; a crashed flow then cannot leave the system in dispatch mode.</li>
|
|
126
|
+
<li><code>mode</code>: default 2 = <i>State of Charge control</i>. Allowed: 1–10 and 19 (<i>No Battery Charge</i>);
|
|
127
|
+
test and off-grid modes are rejected.</li>
|
|
128
|
+
</ul></dd>
|
|
129
|
+
<dt><code>dispatchStop</code></dt>
|
|
130
|
+
<dd>Ends a dispatch immediately. Never blocked by <i>Min. interval</i>.</dd>
|
|
131
|
+
</dl>
|
|
132
|
+
|
|
133
|
+
<h3>Outputs</h3>
|
|
134
|
+
<ol class="node-ports">
|
|
135
|
+
<li>Data – one message per poll cycle
|
|
136
|
+
<dl class="message-properties">
|
|
137
|
+
<dt>payload.consumption <span class="property-type">number</span></dt><dd>house load in W</dd>
|
|
138
|
+
<dt>payload.grid <span class="property-type">number</span></dt><dd>grid power in W, <b>+ import / − export</b></dd>
|
|
139
|
+
<dt>payload.modules <span class="property-type">number</span></dt><dd>PV power in W</dd>
|
|
140
|
+
<dt>payload.battery <span class="property-type">number</span></dt><dd>battery power in W, <b>+ discharge / − charge</b></dd>
|
|
141
|
+
<dt>payload.soc <span class="property-type">number</span></dt><dd>state of charge in %</dd>
|
|
142
|
+
<dt>payload.gridImport / gridExport / batteryCharge / batteryDischarge <span class="property-type">number</span></dt>
|
|
143
|
+
<dd>the same values split by direction, always ≥ 0</dd>
|
|
144
|
+
<dt>payload.autarky <span class="property-type">number</span></dt><dd>share of the house load not covered by the grid, in %</dd>
|
|
145
|
+
<dt>payload.selfConsumptionRate <span class="property-type">number</span></dt><dd>share of the PV power used locally, in %</dd>
|
|
146
|
+
<dt>payload.daily <span class="property-type">object</span></dt>
|
|
147
|
+
<dd>energy in kWh since local midnight: <code>pv</code>, <code>gridFeed</code>, <code>gridImport</code>,
|
|
148
|
+
<code>batteryCharge</code>, <code>batteryDischarge</code>, <code>batteryChargeFromGrid</code>, <code>consumption</code>,
|
|
149
|
+
plus <code>autarky</code>, <code>selfConsumptionRate</code>, <code>since</code> and <code>complete</code></dd>
|
|
150
|
+
<dt>payload.yesterday <span class="property-type">object</span></dt><dd>the daily values of the previous day</dd>
|
|
151
|
+
<dt>payload.alarms / warnings <span class="property-type">array</span></dt><dd>active faults and warnings as text (always English)</dd>
|
|
152
|
+
<dt>payload.blocks <span class="property-type">object</span></dt>
|
|
153
|
+
<dd>per block: <code>age</code> in s since the last successful read, <code>stale</code>, last <code>error</code>,
|
|
154
|
+
and <code>registers</code> if the block fell back to the older register length</dd>
|
|
155
|
+
<dt>payload.details <span class="property-type">object</span></dt>
|
|
156
|
+
<dd>all decoded registers per block (<code>grid</code>, <code>battery</code>, <code>inverter</code>, …)</dd>
|
|
157
|
+
<dt class="optional">payload.info <span class="property-type">object</span></dt><dd>serial numbers (inverter, EMS, WiFi, battery modules) and firmware versions</dd>
|
|
158
|
+
<dt class="optional">errors <span class="property-type">object</span></dt><dd>read errors of this cycle per block</dd>
|
|
159
|
+
</dl>
|
|
160
|
+
<p><code>consumption = modules + grid + battery</code>. The keys <code>consumption</code>, <code>grid</code>, <code>modules</code>,
|
|
161
|
+
<code>battery</code> and <code>soc</code> are the same as in the cloud node <i>node-red-contrib-alphaess</i>.</p>
|
|
162
|
+
</li>
|
|
163
|
+
<li>Alarm – only when alarms or warnings change, and once after start
|
|
164
|
+
<pre>{ "active": true, "alarms": ["System: Grid_Meter_Lost"], "warnings": [], "timestamp": "…" }</pre>
|
|
165
|
+
<code>active</code> is <code>true</code> if at least one alarm is active. Warnings alone do not set <code>active</code>.
|
|
166
|
+
Connect this output to your notification flow.</li>
|
|
167
|
+
<li>Command response – answer to every command except <code>read</code>
|
|
168
|
+
<dl class="message-properties">
|
|
169
|
+
<dt>payload <span class="property-type">object | array</span></dt>
|
|
170
|
+
<dd>the affected block, read back after the command (raw registers for <code>readRaw</code>)</dd>
|
|
171
|
+
<dt class="optional">written <span class="property-type">array</span></dt>
|
|
172
|
+
<dd>written registers, e.g. <code>[{ "address": "0x0850", "values": [200] }]</code>; empty if nothing was written</dd>
|
|
173
|
+
<dt class="optional">unchanged <span class="property-type">boolean</span></dt>
|
|
174
|
+
<dd><code>true</code> if <code>timePeriod</code> / <code>feedIn</code> already had the requested values</dd>
|
|
175
|
+
</dl>
|
|
176
|
+
All other properties of the input message are kept.</li>
|
|
177
|
+
</ol>
|
|
178
|
+
|
|
179
|
+
<h3>Settings</h3>
|
|
180
|
+
<dl class="message-properties">
|
|
181
|
+
<dt>Interval <span class="property-type">s</span></dt>
|
|
182
|
+
<dd>Poll interval for grid, battery, inverter and system data. 10–30 s is a good range. <code>0</code> = only on input.</dd>
|
|
183
|
+
<dt>Slow blocks <span class="property-type">s</span></dt>
|
|
184
|
+
<dd>Interval for system config, time periods and dispatch state (default 300 s). These values rarely change.
|
|
185
|
+
After a write command the affected block is read immediately.</dd>
|
|
186
|
+
<dt>Stale after <span class="property-type">s</span></dt>
|
|
187
|
+
<dd>Time without a successful read after which a block counts as stale (default 180 s). Single failed reads are bridged
|
|
188
|
+
with the last value; stale blocks raise an alarm and are removed from <code>details</code>.
|
|
189
|
+
Should be at least 3 × <i>Interval</i>.</dd>
|
|
190
|
+
<dt>Topic</dt>
|
|
191
|
+
<dd><code>msg.topic</code> of the data messages. The alarm output uses <code><topic>/alarm</code>.</dd>
|
|
192
|
+
<dt>EMS</dt>
|
|
193
|
+
<dd>Selects the texts for battery faults and warnings. The EMS version is shown in <code>info.systemInfo.emsVersion</code>.</dd>
|
|
194
|
+
<dt>Read blocks</dt>
|
|
195
|
+
<dd>
|
|
196
|
+
<ul>
|
|
197
|
+
<li><b>Grid meter</b>, <b>Battery</b>, <b>Inverter</b>: required for consumption, autarky and daily values.</li>
|
|
198
|
+
<li><b>PV meter (AC coupled)</b>: only for systems with an additional, external PV inverter feeding into the house grid.
|
|
199
|
+
Off by default: systems without PV meter would report errors or zeros. Check <code>details.systemConfig</code>:
|
|
200
|
+
<code>systemMode.text</code> = <code>AC</code> / <code>Hybrid</code> or <code>pvCapacityGridInverter</code> > 0
|
|
201
|
+
indicate a PV meter; with <code>DC</code> and <code>0</code> leave it off.</li>
|
|
202
|
+
<li><b>System running data</b>: system faults (e.g. <i>Grid_Meter_Lost</i>, <i>BMS_Lost</i>) and the energy of the external PV inverter.</li>
|
|
203
|
+
<li><b>System config</b>, <b>Time period control</b>, <b>Dispatch state</b>: current settings; needed to see the effect of write commands.</li>
|
|
204
|
+
<li><b>Device info</b>: serial numbers and firmware versions, read at start and once a day.</li>
|
|
205
|
+
</ul></dd>
|
|
206
|
+
<dt>Add PV meter to PV power / daily PV energy</dt>
|
|
207
|
+
<dd>Adds the external PV inverter to <code>modules</code>, <code>consumption</code> and <code>daily.pv</code>.
|
|
208
|
+
Requires the blocks <i>PV meter</i> and <i>System running data</i>.</dd>
|
|
209
|
+
<dt>Daily store</dt>
|
|
210
|
+
<dd>Context store for the daily values. The list shows the stores configured in <code>settings.js</code>.
|
|
211
|
+
With the default in-memory store the daily values start again after every Node-RED restart – see <i>Daily values</i>.</dd>
|
|
212
|
+
<dt>MQTT broker / Prefix / QoS / Retain</dt>
|
|
213
|
+
<dd>Publishes directly to an existing MQTT broker configuration, no MQTT out node needed. See <i>MQTT</i>.</dd>
|
|
214
|
+
<dt>Publish block details as JSON</dt>
|
|
215
|
+
<dd>Additionally publishes every block as JSON to <code><prefix>/details/<block></code>. Larger messages; off by default.</dd>
|
|
216
|
+
<dt>Allow write access</dt>
|
|
217
|
+
<dd>Enables the write commands. Without it, write commands fail with an error and nothing is written.
|
|
218
|
+
When enabled, the node logs a notice at start.</dd>
|
|
219
|
+
<dt>Max. power <span class="property-type">W</span></dt>
|
|
220
|
+
<dd>Upper limit for <code>dispatch</code> power. Recommended: the maximum charge/discharge power of your battery
|
|
221
|
+
(<code>details.battery.maxChargePower</code>).</dd>
|
|
222
|
+
<dt>Min. interval <span class="property-type">s</span></dt>
|
|
223
|
+
<dd>Minimum time between two actual writes of the same command (default 10 s, <code>0</code> = off).
|
|
224
|
+
Protects the EMS against loops in a flow. Requests without change and <code>dispatchStop</code> are not blocked.</dd>
|
|
225
|
+
<dt>SOC scale <span class="property-type">%/bit</span></dt>
|
|
226
|
+
<dd>Resolution of <code>upsReserveSoc</code> and <code>chargeCutSoc</code>. The documentation says 0.1 %/bit, but systems exist
|
|
227
|
+
that use 1 %/bit. <b>Check before the first write:</b> send <code>readRaw</code> with <code>{"address": 2128, "count": 1}</code>.
|
|
228
|
+
If the reserve in the app is 10 % and the raw value is <code>10</code>, set <code>1</code>; if it is <code>100</code>, keep <code>0.1</code>.</dd>
|
|
229
|
+
</dl>
|
|
230
|
+
|
|
231
|
+
<h3>Daily values</h3>
|
|
232
|
+
<p>The system only provides lifetime counters. The node stores the counter values at local midnight and calculates the difference.</p>
|
|
233
|
+
<ul>
|
|
234
|
+
<li><code>daily.since</code>: when counting started. <code>daily.complete</code>: <code>true</code> if counting started within
|
|
235
|
+
15 minutes after midnight – only then do the values cover the whole day. Use it to ignore incomplete days in statistics.</li>
|
|
236
|
+
<li>To keep the values across restarts, add a persistent store to <code>settings.js</code>, restart Node-RED,
|
|
237
|
+
reload the editor and select it as <i>Daily store</i>:
|
|
238
|
+
<pre>contextStorage: {
|
|
239
|
+
default: { module: "memory" },
|
|
240
|
+
file: { module: "localfilesystem" }
|
|
241
|
+
},</pre>
|
|
242
|
+
In Docker (official image) the file is <code>/data/settings.js</code>.</li>
|
|
243
|
+
<li>If the selected store does not exist, Node-RED silently uses the memory store. The node detects this and shows a yellow status
|
|
244
|
+
and a warning.</li>
|
|
245
|
+
<li>The current day cannot be corrected afterwards: the correct values start with the next midnight.</li>
|
|
246
|
+
</ul>
|
|
247
|
+
|
|
248
|
+
<h3>MQTT</h3>
|
|
249
|
+
<p>Topics with the default prefix <code>alphaess</code>:</p>
|
|
250
|
+
<ul>
|
|
251
|
+
<li><code>alphaess/consumption</code>, <code>/grid</code>, <code>/modules</code>, <code>/battery</code>, <code>/soc</code>,
|
|
252
|
+
<code>/gridImport</code>, <code>/gridExport</code>, <code>/batteryCharge</code>, <code>/batteryDischarge</code>,
|
|
253
|
+
<code>/autarky</code>, <code>/selfConsumptionRate</code> – numbers, every cycle</li>
|
|
254
|
+
<li><code>alphaess/daily/<key></code> – daily values, <code>alphaess/daily/complete</code> – <code>true</code>/<code>false</code></li>
|
|
255
|
+
<li><code>alphaess/status</code> – <code>ok</code> or <code>alarm</code></li>
|
|
256
|
+
<li><code>alphaess/alarm</code> – JSON as on output 2, only on change</li>
|
|
257
|
+
<li><code>alphaess/info</code> – JSON, always retained</li>
|
|
258
|
+
<li><code>alphaess/details/<block></code> – JSON, optional</li>
|
|
259
|
+
</ul>
|
|
260
|
+
<p>If you already forward values with your own MQTT nodes, leave the broker empty to avoid duplicate messages.</p>
|
|
261
|
+
|
|
262
|
+
<h3>Examples</h3>
|
|
263
|
+
<h4>Set a value with feedback (link call)</h4>
|
|
264
|
+
<p>Send commands from other tabs with a <i>link call</i> node to a <i>link in</i> node in front of this node.
|
|
265
|
+
To return the response, connect output 3 to a <i>switch</i> on <code>msg._linkSource</code> (<i>is not empty</i>)
|
|
266
|
+
followed by a <i>link out</i> in mode <i>Return to calling link node</i>. Responses of commands that were not sent
|
|
267
|
+
via link call (e.g. an inject node) go to the <i>otherwise</i> output.</p>
|
|
268
|
+
<h4>Reserve SOC depending on the weather forecast</h4>
|
|
269
|
+
<pre>// function node in front of the link call
|
|
270
|
+
const sun = Number(global.get("sunhourstomorrow"));
|
|
271
|
+
if (!Number.isFinite(sun)) return null;
|
|
272
|
+
return { topic: "timePeriod",
|
|
273
|
+
payload: { upsReserveSoc: sun >= 3 ? 10 : 20 } };</pre>
|
|
274
|
+
<p>The command can be sent as often as you like: if the value is already set, nothing is written and the response has
|
|
275
|
+
<code>unchanged: true</code>.</p>
|
|
276
|
+
<h4>Use values in other flows</h4>
|
|
277
|
+
<pre>// function node behind output 1
|
|
278
|
+
global.set("alphaess", msg.payload);
|
|
279
|
+
return { payload: msg.payload.consumption };</pre>
|
|
280
|
+
<h4>Check a single register</h4>
|
|
281
|
+
<pre>{ "topic": "readRaw", "payload": { "address": 1024, "count": 10 } }</pre>
|
|
282
|
+
|
|
283
|
+
<h3>Languages</h3>
|
|
284
|
+
<p>The editor and this help are available in English and German and follow the language setting of the editor.
|
|
285
|
+
Status texts and log messages follow the language of the Node-RED server. Data in <code>msg.payload</code>
|
|
286
|
+
(field names, alarm and warning texts) is always English, so flows work independently of the language.</p>
|
|
287
|
+
|
|
288
|
+
<h3>Disclaimer</h3>
|
|
289
|
+
<ul>
|
|
290
|
+
<li>This is an independent community project. It is <b>not affiliated with, endorsed or supported by Alpha ESS</b>.
|
|
291
|
+
Product names are used only to describe compatibility; trademarks belong to their owners.</li>
|
|
292
|
+
<li>The software is provided <b>"as is", without warranty of any kind</b> (MIT license). Use it <b>at your own risk</b>.</li>
|
|
293
|
+
<li>Reading data does not change the system. <b>Write commands do</b>: wrong values can lead to unwanted grid import,
|
|
294
|
+
a too deep or too shallow discharge, a missing backup reserve, or a feed-in that violates the rules of your grid operator,
|
|
295
|
+
and may affect the manufacturer warranty.</li>
|
|
296
|
+
<li>Enable write access only if you understand the effect of each command. Start with short <code>duration</code> values
|
|
297
|
+
and check the result in the manufacturer app.</li>
|
|
298
|
+
<li>Register addresses and scaling are based on the manufacturer documentation and on tests with individual systems.
|
|
299
|
+
Your model or firmware may behave differently.</li>
|
|
300
|
+
</ul>
|
|
301
|
+
|
|
302
|
+
<h3>Notes</h3>
|
|
303
|
+
<ul>
|
|
304
|
+
<li>After installing a new version, restart Node-RED and reload the editor (F5); otherwise new outputs and settings are not shown.</li>
|
|
305
|
+
<li>Safety test, reset, CT calibration, network/Modbus settings and battery MOS control are intentionally not writable.</li>
|
|
306
|
+
<li>Register addresses and scaling: <i>AlphaESS Household Modbus Register Parameter List</i>. Older firmware that only knows
|
|
307
|
+
the register list V1.1 is detected automatically.</li>
|
|
308
|
+
</ul>
|
|
309
|
+
|
|
310
|
+
<h3>References</h3>
|
|
311
|
+
<ul>
|
|
312
|
+
<li><a href="https://github.com/impact0815/node-red-contrib-alphaess-modbus#readme">README with all fields and register blocks</a></li>
|
|
313
|
+
<li><a href="https://nodered.org/docs/user-guide/context#context-stores">Node-RED: context stores</a></li>
|
|
314
|
+
</ul>
|
|
315
|
+
</script>
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
{
|
|
2
|
+
"alphaess-modbus": {
|
|
3
|
+
"label": {
|
|
4
|
+
"connection": "Connection",
|
|
5
|
+
"host": "Host",
|
|
6
|
+
"port": "Port",
|
|
7
|
+
"unitId": "Unit ID",
|
|
8
|
+
"timeout": "Timeout",
|
|
9
|
+
"delay": "Delay",
|
|
10
|
+
"interval": "Interval",
|
|
11
|
+
"slowInterval": "Slow blocks",
|
|
12
|
+
"staleAfter": "Stale after",
|
|
13
|
+
"topic": "Topic",
|
|
14
|
+
"platform": "EMS",
|
|
15
|
+
"blocks": "Read blocks",
|
|
16
|
+
"includePvMeter": "Add PV meter to PV power / daily PV energy",
|
|
17
|
+
"contextStore": "Daily store",
|
|
18
|
+
"mqttBroker": "Broker",
|
|
19
|
+
"mqttPrefix": "Prefix",
|
|
20
|
+
"mqttQos": "QoS",
|
|
21
|
+
"mqttRetain": "Retain",
|
|
22
|
+
"mqttDetails": "Publish block details as JSON",
|
|
23
|
+
"allowWrite": "Allow write access",
|
|
24
|
+
"maxPower": "Max. power",
|
|
25
|
+
"writeInterval": "Min. interval",
|
|
26
|
+
"socScale": "SOC scale"
|
|
27
|
+
},
|
|
28
|
+
"unit": {
|
|
29
|
+
"unitId": "(default 85 = 0x55)",
|
|
30
|
+
"ms": "ms",
|
|
31
|
+
"delay": "ms between requests",
|
|
32
|
+
"interval": "s (0 = only on input)",
|
|
33
|
+
"slowInterval": "s (config, time periods, dispatch)",
|
|
34
|
+
"staleAfter": "s without successful read",
|
|
35
|
+
"allowWrite": "(dispatch, feed-in, time periods)",
|
|
36
|
+
"maxPower": "W (dispatch limit)",
|
|
37
|
+
"writeInterval": "s between two writes of the same command (0 = off)",
|
|
38
|
+
"socScale": "%/bit for time period SOC values"
|
|
39
|
+
},
|
|
40
|
+
"placeholder": {
|
|
41
|
+
"host": "192.168.1.100",
|
|
42
|
+
"maxPower": "e.g. 5000"
|
|
43
|
+
},
|
|
44
|
+
"block": {
|
|
45
|
+
"grid": "Grid meter",
|
|
46
|
+
"pvMeter": "PV meter (AC coupled)",
|
|
47
|
+
"battery": "Battery",
|
|
48
|
+
"inverter": "Inverter",
|
|
49
|
+
"systemRun": "System running data / system fault",
|
|
50
|
+
"systemConfig": "System config (slow)",
|
|
51
|
+
"timePeriod": "Time period control (slow)",
|
|
52
|
+
"dispatch": "Dispatch state (slow)",
|
|
53
|
+
"info": "Device info (at start, then daily)"
|
|
54
|
+
},
|
|
55
|
+
"section": {
|
|
56
|
+
"mqtt": "MQTT",
|
|
57
|
+
"control": "Control"
|
|
58
|
+
},
|
|
59
|
+
"outputs": {
|
|
60
|
+
"data": "data",
|
|
61
|
+
"alarm": "alarm (on change)",
|
|
62
|
+
"response": "command response"
|
|
63
|
+
},
|
|
64
|
+
"store": {
|
|
65
|
+
"default": "default (__store__)",
|
|
66
|
+
"notConfigured": "__store__ (not configured in settings.js)",
|
|
67
|
+
"missing": "This store does not exist – daily values are not persistent.",
|
|
68
|
+
"onlyMemory": "Only the in-memory store is configured. Add a persistent store (e.g. \"file\") to contextStorage in settings.js to keep daily values across restarts."
|
|
69
|
+
},
|
|
70
|
+
"tip": {
|
|
71
|
+
"writeWarning": "Write commands change how your storage system charges, discharges and feeds into the grid. Use at your own risk – there is no warranty. Make sure the changes are compatible with the manufacturer warranty and the rules of your grid operator.",
|
|
72
|
+
"disclaimer": "Independent community project, not affiliated with Alpha ESS. Provided as is, without warranty."
|
|
73
|
+
},
|
|
74
|
+
"status": {
|
|
75
|
+
"noConnection": "no connection configured",
|
|
76
|
+
"polling": "polling every __interval__ s",
|
|
77
|
+
"manual": "manual mode",
|
|
78
|
+
"storeMissing": "context store \"__store__\" missing in settings.js",
|
|
79
|
+
"storeMissingShort": "store \"__store__\" missing",
|
|
80
|
+
"pv": "PV __value__W",
|
|
81
|
+
"grid": "Grid __value__W",
|
|
82
|
+
"soc": "SOC __value__%",
|
|
83
|
+
"load": "Load __value__W",
|
|
84
|
+
"ok": "ok",
|
|
85
|
+
"unchanged": "__command__: unchanged",
|
|
86
|
+
"written": "__command__: __count__ register(s) written",
|
|
87
|
+
"dispatch": "dispatch __power__W",
|
|
88
|
+
"dispatchStopped": "dispatch stopped"
|
|
89
|
+
},
|
|
90
|
+
"warn": {
|
|
91
|
+
"storeMissing": "Daily values: context store \"__store__\" is not configured in settings.js – daily values are not persistent and restart after every Node-RED restart",
|
|
92
|
+
"writeEnabled": "Write access is enabled. Write commands change the behaviour of the storage system – use at your own risk.",
|
|
93
|
+
"pollRunning": "poll already running – request skipped"
|
|
94
|
+
},
|
|
95
|
+
"log": {
|
|
96
|
+
"fallback": "__block__: extended registers not supported by this system, reading __min__ instead of __count__ registers",
|
|
97
|
+
"unsupported": "__block__: not supported by this system"
|
|
98
|
+
},
|
|
99
|
+
"errors": {
|
|
100
|
+
"writeDisabled": "Writing is disabled – enable \"Allow write access\" in the node settings",
|
|
101
|
+
"rateLimited": "__command__: write blocked, next write possible in __wait__ s (min. interval __interval__ s)",
|
|
102
|
+
"unknownTopic": "Unknown topic \"__topic__\"",
|
|
103
|
+
"addressRange": "payload.address must be 0..65535"
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,55 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"name": "@impact0815/node-red-contrib-alphaess-modbus",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Local Modbus TCP access to Alpha ESS storage systems for Node-RED: realtime data, daily energy, alarms, MQTT and optional control. English and German.",
|
|
5
|
+
"main": "alphaess-modbus.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "node --test test/*.test.js",
|
|
8
|
+
"simulator": "node test/mock-server.js 5020",
|
|
9
|
+
"prepublishOnly": "npm test"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"node-red",
|
|
13
|
+
"alpha-ess",
|
|
14
|
+
"alphaess",
|
|
15
|
+
"storion",
|
|
16
|
+
"smile",
|
|
17
|
+
"modbus",
|
|
18
|
+
"photovoltaic",
|
|
19
|
+
"battery",
|
|
20
|
+
"mqtt"
|
|
21
|
+
],
|
|
22
|
+
"author": "impact0815",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/impact0815/node-red-contrib-alphaess-modbus.git"
|
|
27
|
+
},
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/impact0815/node-red-contrib-alphaess-modbus/issues"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://github.com/impact0815/node-red-contrib-alphaess-modbus#readme",
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=18"
|
|
34
|
+
},
|
|
35
|
+
"node-red": {
|
|
36
|
+
"version": ">=3.0.0",
|
|
37
|
+
"nodes": {
|
|
38
|
+
"alphaess-modbus": "alphaess-modbus.js"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
},
|
|
44
|
+
"files": [
|
|
45
|
+
"alphaess-modbus.js",
|
|
46
|
+
"alphaess-modbus.html",
|
|
47
|
+
"lib/",
|
|
48
|
+
"locales/",
|
|
49
|
+
"examples/",
|
|
50
|
+
"README.md",
|
|
51
|
+
"README.de.md",
|
|
52
|
+
"CHANGELOG.md",
|
|
53
|
+
"LICENSE"
|
|
54
|
+
]
|
|
55
|
+
}
|