node-red-contrib-velbus-2026 0.10.1 → 0.10.2

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.
@@ -29,6 +29,53 @@ separate duplicate-table bugs took to fully resolve.
29
29
 
30
30
  ---
31
31
 
32
+ ## v0.10.2 — 09/07/2026
33
+
34
+ ### velbus-sensor — VMB4AN generic analogue reading (channels 9-12)
35
+
36
+ - **Prompted by Stuart noticing `isVMB4AN` was defined but never used** —
37
+ confirmed the sensor-input channels (Group 2 of VMB4AN's three functional
38
+ groups) produced literally no output at all beforehand; the packet
39
+ carrying that data wasn't handled anywhere in the file.
40
+ - **Real trap found and avoided:** the obviously-named `0xEA`
41
+ ("sensor status") packet does **not** carry a value at all — it's
42
+ operating-mode/sleep-timer/auto-send configuration only. The actual
43
+ reading lives in a separate, easy-to-miss packet earlier in the protocol
44
+ document: `0xA9` (`COMMAND_SENSOR_RAW_DATA`, "Transmit the sensor raw
45
+ value"), genuinely standalone with no need to cross-reference anything
46
+ else. Also confirmed `0xE8`/`0xE9` ("sensor settings") is preset
47
+ *configuration* storage, not a live value either — three different
48
+ packets that could each plausibly have been mistaken for "the reading."
49
+ - Deliberately generic, per explicit preference: emits `{ type: "analogue",
50
+ channel, mode, raw }` with no engineering-unit conversion attempted —
51
+ `mode` (voltage/current/resistance/period) and the PDF's resolution
52
+ table are exposed in the node's help so conversion can happen in the flow
53
+ instead.
54
+ - New `get_analogue` input command (`0xE5`, request-a-reading-now) — uses
55
+ the protocol's own "auto-send config byte = 0" option to request a value
56
+ without side-effecting the module's existing auto-send schedule.
57
+ **Priority byte corrected during verification:** the protocol PDF
58
+ explicitly states "SID10-SID9 = 11 (lowest priority)" for this specific
59
+ command — `0xFB`, not the `0xF8` most other commands in this file use.
60
+ Checked directly rather than assumed, since this is the one place it
61
+ genuinely differs from the file's established convention.
62
+ - Both confirmed absent from `VMB7IN`'s own protocol PDF before wiring
63
+ in — this file's switch statement handles both module types together,
64
+ so a collision would misfire for `VMB7IN` modules if either byte had
65
+ been reused there.
66
+ - **Full Group 2 configuration (presets, mode-switching, sleep time,
67
+ offset, auto-send interval config) and all of Group 3 (analog outputs)
68
+ remain parked** — see `coverage-roadmap.md` section 6. This is
69
+ deliberately just the minimal reading piece, not the full feature.
70
+
71
+ Verified via the mock-RED harness: voltage/period modes, both period
72
+ special-value cases (`0x000000` short-circuit, `0xFFFFFF` open-circuit),
73
+ `VMB7IN` isolation confirmed (same bytes produce no output on that type),
74
+ `get_analogue` checksum hand-verified, correctly rejected on non-VMB4AN
75
+ types. Not yet sent to a real bus.
76
+
77
+ ---
78
+
32
79
  ## v0.10.1 — 09/07/2026
33
80
 
34
81
  ### Two critical bugs found on real hardware — velbus-dimmer and velbus-glass-panel
package/HANDOVER.md CHANGED
@@ -6,7 +6,7 @@ you're a new contributor, a new maintainer, or an AI assistant starting a fresh
6
6
  with no memory of previous work — this document should be sufficient on its own, together
7
7
  with the source code in this repository, to continue development competently.
8
8
 
9
- Current state at time of writing: **v0.10.1, 19 nodes, published on npm.**
9
+ Current state at time of writing: **v0.10.2, 19 nodes, published on npm.**
10
10
 
11
11
  ---
12
12
 
@@ -306,7 +306,7 @@ or a string before assuming the parsing logic itself is wrong.
306
306
  | `velbus-pir` | Velbus (inputs) | Original-series PIR: VMBPIRO-10, VMBPIRM, VMBPIRC, VMBPIRO |
307
307
  | `velbus-pir-20` | Velbus (inputs) | V2 PIR: VMBPIR-20, VMBPIRO-20 |
308
308
  | `velbus-meteo` | Velbus (inputs) | Weather station: VMBMETEO |
309
- | `velbus-sensor` | Velbus (inputs) | Original-series input/analogue: VMB7IN, VMB4AN, VMB6IN |
309
+ | `velbus-sensor` | Velbus (inputs) | Original-series input/analogue: VMB7IN, VMB4AN (channels 1-8 alarm outputs + generic analogue reading on channels 9-12; full sensor/preset config and analog outputs on channels 13-16 remain parked), VMB6IN |
310
310
  | `velbus-sensor-20` | Velbus (inputs) | V2 input: VMB8IN-20 |
311
311
  | `velbus-blind` | Velbus (outputs) | VMB1BL, VMB2BL |
312
312
  | `velbus-blind-s` | Velbus (outputs) | VMB1BLS, VMB2BLE, VMB2BLE-10 |
@@ -589,6 +589,23 @@ Address assignment: allow 500ms, then rescan to confirm the new address took eff
589
589
  not the right trigger for an automatic write-back, both for the EEPROM-wear reason above
590
590
  and because it risks a feedback loop. Reads have no such constraint and are always safe.
591
591
 
592
+ ### 7.8a `VMB4AN` — three similar-sounding packets, only one has the actual value
593
+
594
+ A real trap, worth remembering for any future work on this module's
595
+ sensor channels (9-12): `0xEA` ("sensor status") sounds like it should be
596
+ the reading, but it's operating-mode/sleep-timer/auto-send configuration
597
+ only — no value field at all. `0xE8`/`0xE9` ("sensor settings") sounds
598
+ promising too, but that's stored preset *configuration*, not a live
599
+ reading. The actual value lives in `0xA9` (`COMMAND_SENSOR_RAW_DATA`,
600
+ labelled "Transmit the sensor raw value" in the PDF) — a completely
601
+ standalone packet with no need to cross-reference either of the other two.
602
+ ```
603
+ body[0] = 0xA9, body[1] = channel (9-12)
604
+ body[2] = operating mode (00=voltage, 01=current, 10=resistance, 11=period)
605
+ body[3-5] = 24-bit raw value, MSB first
606
+ (period mode: 0x000000 = short-circuited, 0xFFFFFF = open-circuit)
607
+ ```
608
+
592
609
  ### 7.9 Thermostat commands — always to the primary address
593
610
  ```
594
611
  0xDB = comfort mode, 0xDC = day mode, 0xDD = night mode, 0xDE = safe mode
@@ -137,12 +137,24 @@
137
137
  "enabled": [1,2,3,4,5,6,7,8], "locked": [], "progDisabled": [],
138
138
  "program": "summer", "alarms": { "alarm1Active": false, "alarm2Active": false } }</pre>
139
139
 
140
- <h3>Output 2 — Counter data (VMB7IN only)</h3>
140
+ <h3>Output 2 — Counter data (VMB7IN) / Analogue readings (VMB4AN)</h3>
141
141
  <pre>{ "type": "counter", "channel": 1, "count": 12345,
142
142
  "pulsesPerUnit": 1000, "periodMs": 3600, "overflow": false }</pre>
143
143
  <p>Engineering units: calculate in flow using pulsesPerUnit and periodMs.</p>
144
144
  <p>Power (W) = 3,600,000,000 / (periodMs × pulsesPerUnit)</p>
145
145
 
146
+ <p>VMB4AN sensor channels (9-12) — deliberately generic, no engineering-unit
147
+ conversion attempted here (mode-aware scaling, presets, and sleep-timer
148
+ configuration are a larger, separately-scoped piece of work — see
149
+ <code>coverage-roadmap.md</code>):</p>
150
+ <pre>{ "type": "analogue", "channel": 9, "mode": "voltage", "raw": 12345 }</pre>
151
+ <p><code>mode</code> is <code>"voltage"</code> (0-10V, 0.25mV/count),
152
+ <code>"current"</code> (4-20mA, 5µA/count), <code>"resistance"</code>
153
+ (PT100/PT1000/Ni1000, 0.25Ω/count), or <code>"period"</code> (0.5µs/count —
154
+ <code>raw</code> of <code>0</code> means short-circuited, <code>16777215</code>
155
+ means open-circuit). Apply the resolution yourself in the flow, e.g.
156
+ <code>volts = raw * 0.00025</code> for voltage mode.</p>
157
+
146
158
  <h3>Input commands</h3>
147
159
  <dl>
148
160
  <dt><code>{ "cmd": "get_status" }</code></dt><dd>Request module status.</dd>
@@ -150,6 +162,10 @@
150
162
  <dd>Request counter (VMB7IN). channels=bitmask of ch1-4 (default 15=all). interval=0 no change.</dd>
151
163
  <dt><code>{ "cmd": "reset_counter", "channel": 1 }</code></dt><dd>Reset pulse counter to zero.</dd>
152
164
  <dt><code>{ "cmd": "load_counter", "channel": 1, "value": 12345 }</code></dt><dd>Load counter with preset value (build 1426+).</dd>
165
+ <dt><code>{ "cmd": "get_analogue", "channel": 9 }</code></dt>
166
+ <dd>Request an analogue reading now (VMB4AN, channel 9-12). Doesn't change
167
+ the module's own auto-send interval configuration — it already sends
168
+ readings on its own schedule; this just asks for one immediately.</dd>
153
169
  <dt><code>{ "cmd": "get_name", "channel": 1 }</code></dt><dd>Request channel name from VelbusLink.</dd>
154
170
  </dl>
155
171
  </script>
@@ -172,6 +172,34 @@ module.exports = function(RED) {
172
172
  break;
173
173
  }
174
174
 
175
+ // ── 0xA9 Sensor raw value (VMB4AN channels 9-12 only) ────────────
176
+ // Confirmed from protocol_vmb4an.pdf, "Transmit the sensor raw
177
+ // value" — a genuinely standalone packet (COMMAND_SENSOR_RAW_DATA),
178
+ // not to be confused with 0xEA "sensor status" (that one carries
179
+ // operating mode / sleep timer / auto-send config, no actual value
180
+ // at all — a real trap if you assume "status" means "reading").
181
+ // body[0]=0xA9, body[1]=channel(9-12), body[2]=operating mode,
182
+ // body[3-5]=24-bit raw value (upper/high/low, MSB first).
183
+ // Deliberately generic per Stuart's own preference — engineering-
184
+ // unit conversion (voltage/current/resistance/period) is left to
185
+ // the flow, not attempted here. The PDF's resolution table (e.g.
186
+ // 0.25mV/count for voltage) is available in this node's help if
187
+ // conversion is ever wanted downstream.
188
+ case 0xA9: {
189
+ if (!isVMB4AN) return;
190
+ if (body.length < 6) return;
191
+
192
+ const channel = body[1];
193
+ const modeCode = body[2] & 0x03;
194
+ const mode = ['voltage', 'current', 'resistance', 'period'][modeCode];
195
+ const raw = (body[3] << 16) | (body[4] << 8) | body[5];
196
+
197
+ const payload = { type: 'analogue', channel, mode, raw };
198
+
199
+ node.send([null, { payload }]);
200
+ break;
201
+ }
202
+
175
203
  // ── 0xF0/F1/F2 Channel name parts ───────────────────────────────
176
204
  case 0xF0:
177
205
  case 0xF1:
@@ -222,6 +250,25 @@ module.exports = function(RED) {
222
250
  return;
223
251
  }
224
252
 
253
+ // Request an analogue reading now — VMB4AN channels 9-12 only.
254
+ // DATABYTE3=0 explicitly means "don't change the auto-send interval
255
+ // config" per the protocol PDF — this just asks for a value without
256
+ // side effects on the module's existing auto-send behaviour.
257
+ // Priority: protocol PDF explicitly states "SID10-SID9 = 11 (lowest
258
+ // priority)" for this specific command — 0xFB, not the 0xF8 used by
259
+ // most other commands in this file. Checked directly rather than
260
+ // assumed, since this is the one place it genuinely differs.
261
+ if (cmd === 'get_analogue') {
262
+ if (!isVMB4AN) { node.warn('velbus-sensor: this module has no analogue sensor channels'); return; }
263
+ const ch = parseInt(msg.payload.channel);
264
+ if (!ch || ch < 9 || ch > 12) {
265
+ node.warn('velbus-sensor: get_analogue requires "channel": 9-12');
266
+ return;
267
+ }
268
+ node.bridge.send(pkt(0xFB, node.address, [0xE5, ch, 0x00]));
269
+ return;
270
+ }
271
+
225
272
  // Load counter — DB2=channel number (0-3), DB3=don't care, DB4-7=32-bit value
226
273
  if (cmd === 'load_counter') {
227
274
  if (!hasCounter) { node.warn('velbus-sensor: this module has no pulse counter'); return; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-velbus-2026",
3
- "version": "0.10.1",
3
+ "version": "0.10.2",
4
4
  "description": "Node-RED palette for Velbus building automation \u2014 relay, dimmer, glass panel, PIR, blind, sensor, meteo, clock nodes. Original and V2 (-20) series.",
5
5
  "keywords": [
6
6
  "node-red",
Binary file