node-red-contrib-velbus-2026 0.9.3 → 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.
- package/CHANGELOG_FORUM.md +255 -0
- package/HANDOVER.md +192 -21
- package/lib/glass-panel-types.js +36 -0
- package/lib/sensor-types.js +19 -0
- package/nodes/velbus-button/velbus-button.html +71 -16
- package/nodes/velbus-button/velbus-button.js +226 -14
- package/nodes/velbus-clock/velbus-clock.html +21 -0
- package/nodes/velbus-clock/velbus-clock.js +36 -0
- package/nodes/velbus-dimmer/velbus-dimmer.html +9 -0
- package/nodes/velbus-dimmer/velbus-dimmer.js +66 -35
- package/nodes/velbus-glass-panel/velbus-glass-panel.html +2 -0
- package/nodes/velbus-glass-panel/velbus-glass-panel.js +4 -2
- package/nodes/velbus-scan/velbus-scan.js +34 -0
- package/nodes/velbus-sensor/velbus-sensor.html +18 -1
- package/nodes/velbus-sensor/velbus-sensor.js +47 -0
- package/package.json +1 -1
- package/velbus-2026-repo.bundle +0 -0
- package/velbus-2026-repo.bundle.1 +0 -0
package/CHANGELOG_FORUM.md
CHANGED
|
@@ -14,6 +14,261 @@ All feedback via GitHub issues, with examples and debug captures where possible.
|
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
17
|
+
## Field-confirmed — 09/07/2026
|
|
18
|
+
|
|
19
|
+
**v0.9.3 confirmed working against real hardware** (Stuart, his own home
|
|
20
|
+
installation). Both real VMBGPOD panels present on the bus (addresses 0x05
|
|
21
|
+
and 0x18/0x2C) now report correctly — `"module":"VMBGPOD"`, correct
|
|
22
|
+
suggested node, correct channel count — where a rescan previously showed
|
|
23
|
+
`unknown_0x28` twice. The only remaining unknown in the same scan is
|
|
24
|
+
`unknown_0x42` (VMBKP, address 0xFD on Stuart's bus) — expected and correct,
|
|
25
|
+
since that module genuinely has no node built yet. This closes out the
|
|
26
|
+
VMBGPOD saga (v0.9.2 → v0.9.3) with an actual confirmed result, not just
|
|
27
|
+
passing tests — worth the distinction given how much back-and-forth two
|
|
28
|
+
separate duplicate-table bugs took to fully resolve.
|
|
29
|
+
|
|
30
|
+
---
|
|
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
|
+
|
|
79
|
+
## v0.10.1 — 09/07/2026
|
|
80
|
+
|
|
81
|
+
### Two critical bugs found on real hardware — velbus-dimmer and velbus-glass-panel
|
|
82
|
+
|
|
83
|
+
**velbus-dimmer — `on`/`state` always wrong for original-series dimmers.**
|
|
84
|
+
Reported by Stuart: a VMBDMI at 75% dim showing `state:"off"`, `on:false`.
|
|
85
|
+
Root cause was a genuine misunderstanding of the protocol, not a small
|
|
86
|
+
off-by-one: `0xB8`'s `DATABYTE3` packs run-mode, error, load-type, and
|
|
87
|
+
temperature band **all into one status byte** (confirmed identical across
|
|
88
|
+
`protocol_vmbdmi.pdf`, `protocol_vmbdmi_r.pdf`, and `protocol_vmb4dc.pdf`).
|
|
89
|
+
The previous code treated this as if it were a separate mode-byte +
|
|
90
|
+
status-byte pair (the way relay modules genuinely have), and additionally
|
|
91
|
+
read `DATABYTE5` (LED indicator status — real values `0x00`/`0x80`/`0x40`/
|
|
92
|
+
`0x20`/`0x10`) as a second status word, checking its low 2 bits for
|
|
93
|
+
confirmation. Since none of the real LED status values have those bits
|
|
94
|
+
set, a dimmer in ordinary "normal running" mode — the overwhelmingly
|
|
95
|
+
common case — always fell through to `'off'`, regardless of actual dim
|
|
96
|
+
level. Also fixed in the same pass: the 24-bit current-delay timer was
|
|
97
|
+
being read as only 16 bits from the wrong byte offset, and `decodeThermal`
|
|
98
|
+
was being called on the LED byte instead of the real status byte (explains
|
|
99
|
+
why `thermal` always showed all zeros in the field report). `ledState` is
|
|
100
|
+
now correctly decoded and added to the payload. Verified against the exact
|
|
101
|
+
reported scenario plus inhibited/forced_on/disabled/thermal-alarm cases,
|
|
102
|
+
with the bit-field math for the packed status byte hand-checked.
|
|
103
|
+
|
|
104
|
+
**velbus-glass-panel — `0xEA` thermostat status has been silently crashing
|
|
105
|
+
since it was written.** Reported by Stuart via a `"velbus-bridge dispatch
|
|
106
|
+
error: currentTemp is not defined"` message appearing repeatedly while
|
|
107
|
+
testing a VMBGP2. Root cause: `currentTemp` and `targetTemp` were only ever
|
|
108
|
+
assigned as properties of the `payload` object literal, never declared as
|
|
109
|
+
their own variables — but the very next line referenced them as bare
|
|
110
|
+
identifiers in the `setStatus(...)` call. Because JS evaluates a function's
|
|
111
|
+
arguments before calling it, this threw a `ReferenceError` before
|
|
112
|
+
`node.send()` on the following line ever executed. **This means the
|
|
113
|
+
`type:"thermostat"` payload has likely never once been successfully
|
|
114
|
+
delivered for any thermostat-equipped glass panel** — the bridge's
|
|
115
|
+
dispatch-error handling caught the exception each time rather than
|
|
116
|
+
crashing the whole process, which is exactly why this went unnoticed for
|
|
117
|
+
so long rather than being immediately obvious. Fixed by declaring both as
|
|
118
|
+
proper local `const`s before use. Did a full sweep of every other packet
|
|
119
|
+
case in this file (button, module status, temperature, light sensor, memo
|
|
120
|
+
text, counter, name parts) via the mock harness afterward, specifically
|
|
121
|
+
exercising the OLED- and PIR-gated branches too — no other instances
|
|
122
|
+
found. Also swept every other node file for the same bare-identifier
|
|
123
|
+
`.toFixed()` pattern that caused this — one other match (`velbus-meteo`)
|
|
124
|
+
checked and confirmed already correct (properly prefixed with `payload.`).
|
|
125
|
+
|
|
126
|
+
Both verified via the mock-RED harness against the exact reported symptoms
|
|
127
|
+
before and after the fix — not just re-reading the corrected code. Not yet
|
|
128
|
+
re-confirmed on Stuart's real hardware.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## v0.10.0 — 09/07/2026
|
|
133
|
+
|
|
134
|
+
### Coverage roadmap implementation — 9 new module types, velbus-button overhaul, velbus-clock sunrise/sunset
|
|
135
|
+
|
|
136
|
+
Following a full rationalization pass over every unaddressed Velbus module
|
|
137
|
+
type and feature (see `coverage-roadmap.md`), this implements everything
|
|
138
|
+
confirmed in scope. Every single item below was checked against its actual
|
|
139
|
+
protocol document before being added — several real divergences were caught
|
|
140
|
+
in the process that would otherwise have shipped silently wrong.
|
|
141
|
+
|
|
142
|
+
**velbus-button — substantial overhaul, not just new registry entries:**
|
|
143
|
+
- 7 new module types: VMB8IR, VMB4PD, VMB4RF, VMBRFR8S, VMBVP01, VMBKP, VMBIN.
|
|
144
|
+
- **Lock/unlock (0x12/0x13)** — confirmed present on 8 of the 12 total types
|
|
145
|
+
now covered; **NOT universal**, despite being asked for as "a key Velbus
|
|
146
|
+
feature." VMB8PB, VMB8IR, VMB4PD, and VMBVP01 genuinely lack this command
|
|
147
|
+
in their own protocol documents. Gated per-type (`hasLock`) — sending it to
|
|
148
|
+
an unsupported type now warns clearly on output 2 rather than silently
|
|
149
|
+
doing nothing.
|
|
150
|
+
- **Richer 0xED status decode** (locked/enabled/inverted/program-disabled) —
|
|
151
|
+
also NOT universal. VMB8PB's 0xED is a completely different, simpler
|
|
152
|
+
LED-only format; VMB4RF's status uses command byte 0xB4, not 0xED, with a
|
|
153
|
+
different field at DATABYTE4 ("learn transmitter mode"); VMBVP01's 0xED is
|
|
154
|
+
a third, shorter shape again. Gated per-type (`hasRichStatus`) — decoding
|
|
155
|
+
is skipped entirely for types that don't match, rather than risk
|
|
156
|
+
misreading whatever they actually send.
|
|
157
|
+
- **Channel names surfaced in event output** (0xF0/F1/F2) — found the
|
|
158
|
+
selector byte convention itself is inconsistent across types: some use a
|
|
159
|
+
bitmask (one bit per channel), others a literal 1-based number. These
|
|
160
|
+
produce the *same* byte value for channels 1-2, diverging only from
|
|
161
|
+
channel 3 onward — exactly the kind of thing that would pass casual
|
|
162
|
+
testing and then silently corrupt every name from channel 3 up. Verified
|
|
163
|
+
explicitly at channel 3 for both conventions before shipping.
|
|
164
|
+
- **VMBVP01 (DoorBird)** gets fixed semantic channel labels (Motion 1/2,
|
|
165
|
+
Bell 1/2, Door 1/2, Virtual button 1/2) — hardware-fixed functions, not
|
|
166
|
+
VelbusLink-configurable names, so not sourced from 0xF0-F2 at all.
|
|
167
|
+
- Output changed from 1 to 2 (events/status, warnings) — non-breaking for
|
|
168
|
+
existing flows, the new output simply has no wires by default.
|
|
169
|
+
- **Real mistake caught before shipping:** first pass had VMB4RF at 8
|
|
170
|
+
channels; its own status packet says "channel 1 to 4," matching its name.
|
|
171
|
+
Corrected to 4 before release, not after.
|
|
172
|
+
- **A second, more serious pre-existing bug found and fixed, unrelated to
|
|
173
|
+
today's additions:** `VMB4PB` and `VMB6PB-20` — two of the *original* five
|
|
174
|
+
button types, present since v0.5.2 — were registered under wrong type
|
|
175
|
+
bytes (`0x1C` and `0x20`) in this file's own registry. `0x1C` isn't a real
|
|
176
|
+
Velbus type byte at all; `0x20` actually belongs to `VMBGP4`, an unrelated
|
|
177
|
+
glass panel type. `velbus-scan.js` has always had the correct values
|
|
178
|
+
(`0x44`/`0x4C`) — only this file's internal lookup was wrong, meaning a
|
|
179
|
+
real `VMB4PB` or `VMB6PB-20`, correctly identified by a scan, would never
|
|
180
|
+
have matched this file's own type descriptor at all. Every type-specific
|
|
181
|
+
feature (and now, lock/unlock and rich status too) would have silently
|
|
182
|
+
never activated for these two types. Found by cross-referencing the
|
|
183
|
+
official type list while writing this changelog entry, not by design —
|
|
184
|
+
worth remembering that documentation review can surface real bugs too.
|
|
185
|
+
|
|
186
|
+
**velbus-sensor:** VMB6IN added. Confirmed simpler than its VMB7IN sibling,
|
|
187
|
+
not just a smaller version of it — no lock/unlock command exists for it at
|
|
188
|
+
all, and its 0xED module status is 5 bytes vs VMB7IN's 7. The existing
|
|
189
|
+
`body.length < 7` guard already skips it safely; no code change needed
|
|
190
|
+
beyond the registry entry itself.
|
|
191
|
+
|
|
192
|
+
**velbus-glass-panel:** VMBGP4PIR-2 (0x3E) and VMBGPTC (0x25) added.
|
|
193
|
+
- **Real mistake caught:** VMBGP4PIR-2's channels 5-8 have completely
|
|
194
|
+
different semantics from its 0x2D sibling despite the near-identical name
|
|
195
|
+
(Dark/Light output, Motion output, Light-depending-motion, Absence output
|
|
196
|
+
— not virtual/dark/light/motion). Copying the sibling's mapping would have
|
|
197
|
+
silently mislabeled four channels.
|
|
198
|
+
- VMBGPTC confirmed sharing its actual protocol document with VMBGPO
|
|
199
|
+
(0x21) — a thermostat-only variant of the same panel hardware, added to
|
|
200
|
+
the glass-panel registry rather than as thermostat-node-only, so
|
|
201
|
+
`velbus-thermostat` picks up its function automatically the same way it
|
|
202
|
+
already does for every other panel address.
|
|
203
|
+
|
|
204
|
+
**velbus-clock:** sunrise/sunset enable/disable (0xAE) added, same
|
|
205
|
+
global/local address pattern as the existing `set_alarm` — confirmed
|
|
206
|
+
identical packet body for both from the protocol PDF.
|
|
207
|
+
|
|
208
|
+
**velbus-scan:** all of the above added across its three independent tables
|
|
209
|
+
(`ALL_TYPES`/`NODE_SUGGESTION`/`MODULE_CHANNELS`) — the exact lesson from
|
|
210
|
+
the VMBGPOD saga (v0.9.2/v0.9.3), applied proactively this time rather than
|
|
211
|
+
discovered the hard way again. Also adds explicit `"Not supported"` scan
|
|
212
|
+
labels (rather than falling through to a bare name with no node) for
|
|
213
|
+
VMBDALI, VMBDALI-20, VMBLCDWB, VMCM3, VMBSIG, VMBSIG-20, and VMBSIG-21 —
|
|
214
|
+
recognized correctly in a scan, deliberately not built, by design rather
|
|
215
|
+
than oversight.
|
|
216
|
+
|
|
217
|
+
**Explicitly deferred, not built this round:** VMB1DM, VMBDME, and VMB1LED
|
|
218
|
+
(the dimmer-family additions) all turned out to use a genuinely different
|
|
219
|
+
single-channel `0xEE` status layout — distinct from both `velbus-dimmer`'s
|
|
220
|
+
own format and `velbus-dimmer-20`'s multi-channel bitmask format. This needs
|
|
221
|
+
real new decode logic, not a registry entry, and doesn't meet the
|
|
222
|
+
"minimal effort" bar set for this round. Parked rather than forced in.
|
|
223
|
+
|
|
224
|
+
**Verification:** every new packet format checked against its actual
|
|
225
|
+
protocol document (not inferred from a same-named sibling) before being
|
|
226
|
+
implemented; every new command exercised through the mock-RED harness with
|
|
227
|
+
hand-checked checksums; the channel-3 naming-convention divergence
|
|
228
|
+
specifically tested for both conventions, not just one; a full simulated
|
|
229
|
+
scan run across every new and "not supported" type confirmed correct
|
|
230
|
+
`suggestedNode`/`channels` output end to end. Not yet sent to a real bus.
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## v0.9.4 — 09/07/2026
|
|
235
|
+
|
|
236
|
+
### velbus-button — critical bug, live since v0.5.2: button events shifted by one byte
|
|
237
|
+
|
|
238
|
+
- **Found while scoping VMBKP's decode logic, not reported directly** — checking
|
|
239
|
+
`velbus-button.js` as a template surfaced that its `0x00` handler read
|
|
240
|
+
`body[0]`/`body[1]`/`body[2]` for pressed/released/long-pressed, when
|
|
241
|
+
`body[0]` is always the command byte itself (always `0x00`, per this
|
|
242
|
+
project's own most-repeated rule — see `HANDOVER.md` section 4.3). Every
|
|
243
|
+
field was reading one byte too early.
|
|
244
|
+
- **Real impact, not theoretical:** `pressed` was always empty (reading the
|
|
245
|
+
constant command byte), `released` was actually reporting what DATABYTE2
|
|
246
|
+
(the real "pressed" bitmask) contained, `longPressed` was reporting what
|
|
247
|
+
DATABYTE3 (the real "released" bitmask) contained, and the real
|
|
248
|
+
DATABYTE4 (long-press bitmask) was never read at all. The `on` field
|
|
249
|
+
followed the same corruption — it could report `true` on a release and
|
|
250
|
+
never correctly on an immediate press.
|
|
251
|
+
- **Confirmed live since `velbus-button`'s introduction in v0.5.2** — this
|
|
252
|
+
is not a new regression, it has been shipping incorrect button-event data
|
|
253
|
+
for the entire time this node has existed. `velbus-glass-panel`'s own
|
|
254
|
+
`0x00` handler was checked immediately afterward and confirmed **not**
|
|
255
|
+
affected — it already used the correct `body[1]`/`body[2]`/`body[3]`
|
|
256
|
+
indexing, so this was isolated to one file, not systemic.
|
|
257
|
+
- **Fixed and verified with a real repro, not just a corrected read of the
|
|
258
|
+
code:** built a mock-harness test that reproduces the exact failure first
|
|
259
|
+
(channel 3 pressed came back reported as "released") before applying the
|
|
260
|
+
fix, then re-ran the same test plus three more (release, long-press,
|
|
261
|
+
simultaneous multi-channel press) to confirm all four now report
|
|
262
|
+
correctly.
|
|
263
|
+
- **If you have flows depending on `velbus-button`'s `pressed`/`released`/
|
|
264
|
+
`longPressed` distinction** (rather than just the `on` boolean, or
|
|
265
|
+
scanning/discovery, which were unaffected), check them after updating —
|
|
266
|
+
behaviour that previously "worked" by only watching `on`, or by
|
|
267
|
+
compensating for the shift some other way in the flow itself, may now
|
|
268
|
+
behave differently now that the underlying data is actually correct.
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
17
272
|
## v0.9.3 — 09/07/2026
|
|
18
273
|
|
|
19
274
|
### velbus-scan — VMBGPOD still showed "unknown_0x28" after the v0.9.2 fix
|
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.
|
|
9
|
+
Current state at time of writing: **v0.10.2, 19 nodes, published on npm.**
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
@@ -106,7 +106,7 @@ lib/ Shared code — protocol utilities and per-module-fam
|
|
|
106
106
|
dimmer-types.js Original-series dimmer module type registry
|
|
107
107
|
dimmer-types-20.js V2 dimmer module type registry (incl. LED grouping mode / Device
|
|
108
108
|
Type table for VMB4LEDPWM-20)
|
|
109
|
-
glass-panel-types.js All
|
|
109
|
+
glass-panel-types.js All 29 glass panel module types in one registry (hasOled/hasPir/
|
|
110
110
|
hasOc/minMapVer flags per type)
|
|
111
111
|
pir-types.js / pir-types-20.js PIR sensor module type registries
|
|
112
112
|
sensor-types.js / sensor-types-20.js Sensor/meteo module type registries
|
|
@@ -262,6 +262,22 @@ implementing a new packet handler, always write out the DATABYTE-to-`body[]` ind
|
|
|
262
262
|
mapping explicitly as a comment before writing the parsing logic — it is not something
|
|
263
263
|
to trust from memory or infer quickly.
|
|
264
264
|
|
|
265
|
+
**The canonical real example: `velbus-button` shipped this exact bug from its very
|
|
266
|
+
first version (v0.5.2) until v0.9.4** — over 30 versions, undetected. Its `0x00`
|
|
267
|
+
handler read `body[0]`/`body[1]`/`body[2]` for pressed/released/long-pressed, when the
|
|
268
|
+
correct indices are `body[1]`/`body[2]`/`body[3]`. The practical effect: `pressed` was
|
|
269
|
+
always empty (silently reading the constant command byte), `released` actually reported
|
|
270
|
+
what was really the pressed bitmask, `longPressed` reported what was really the released
|
|
271
|
+
bitmask, and the real long-press data was never read at all. It went unnoticed for this
|
|
272
|
+
long specifically because `velbus-glass-panel`'s own, separately-written `0x00` handler
|
|
273
|
+
got the indexing right from the start, and nobody had directly exercised
|
|
274
|
+
`velbus-button`'s press/release distinction against real hardware — only its
|
|
275
|
+
scan/discovery path (`0xFF`/`0xB0`, handled entirely separately) had seen real traffic.
|
|
276
|
+
A bug in one packet handler is invisible from the outside if nothing forces that
|
|
277
|
+
specific handler to run against real data. If you're verifying a node, verify the
|
|
278
|
+
specific packet type you care about — passing scan/discovery doesn't imply anything
|
|
279
|
+
about a different command byte's handler in the same file.
|
|
280
|
+
|
|
265
281
|
### 4.4 Address format
|
|
266
282
|
|
|
267
283
|
Module addresses are stored as **hex strings in the editor's dropdown UI** (e.g.
|
|
@@ -284,18 +300,18 @@ or a string before assuming the parsing logic itself is wrong.
|
|
|
284
300
|
| `velbus-relay-20` | Velbus (outputs) | V2 relays: VMB1RYS-20, VMB4RYLD-20, VMB4RYNO-20 |
|
|
285
301
|
| `velbus-dimmer` | Velbus (outputs) | Original-series dimmers: VMBDMI, VMBDMI-R, VMB4DC |
|
|
286
302
|
| `velbus-dimmer-20` | Velbus (outputs) | V2 dimmers: VMB2DC-20, VMB8DC-20, VMB4LEDPWM-20 (incl. RGB/RGBW grouping mode) |
|
|
287
|
-
| `velbus-glass-panel` | Velbus (inputs) | All
|
|
303
|
+
| `velbus-glass-panel` | Velbus (inputs) | All 29 glass panel types (original + V2), buttons/OLED/PIR/open-collector as applicable per type |
|
|
288
304
|
| `velbus-thermostat` | Velbus (inputs) | Thermostat function on any glass panel module that has one — same address as the corresponding glass-panel node, coexists without conflict |
|
|
289
|
-
| `velbus-button` | Velbus (inputs) |
|
|
305
|
+
| `velbus-button` | Velbus (inputs) | 12 types across original and V2 series (VMB8PB, VMB8PBU, VMB6PBN, VMB2PBN, VMB4PB, VMB6PB-20, VMB8IR, VMB4PD, VMB4RF, VMBRFR8S, VMBVP01, VMBKP, VMBIN) — plain button events for all; lock/unlock and richer status decode for the 8 types confirmed to support them; fixed semantic channel labels for VMBVP01 (DoorBird) |
|
|
290
306
|
| `velbus-pir` | Velbus (inputs) | Original-series PIR: VMBPIRO-10, VMBPIRM, VMBPIRC, VMBPIRO |
|
|
291
307
|
| `velbus-pir-20` | Velbus (inputs) | V2 PIR: VMBPIR-20, VMBPIRO-20 |
|
|
292
308
|
| `velbus-meteo` | Velbus (inputs) | Weather station: VMBMETEO |
|
|
293
|
-
| `velbus-sensor` | Velbus (inputs) | Original-series input/analogue: VMB7IN, VMB4AN |
|
|
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 |
|
|
294
310
|
| `velbus-sensor-20` | Velbus (inputs) | V2 input: VMB8IN-20 |
|
|
295
311
|
| `velbus-blind` | Velbus (outputs) | VMB1BL, VMB2BL |
|
|
296
312
|
| `velbus-blind-s` | Velbus (outputs) | VMB1BLS, VMB2BLE, VMB2BLE-10 |
|
|
297
313
|
| `velbus-blind-20` | Velbus (outputs) | VMB2BLE-20 |
|
|
298
|
-
| `velbus-clock` | Velbus (outputs) | **No fixed module address.** Broadcasts system time/date/DST to the bus broadcast address (`0x00`),
|
|
314
|
+
| `velbus-clock` | Velbus (outputs) | **No fixed module address.** Broadcasts system time/date/DST to the bus broadcast address (`0x00`), sets clock alarms and sunrise/sunset enable state either globally (broadcast) or locally (a specific module, via a per-message address override) |
|
|
299
315
|
| `velbus-energy` | Velbus (inputs) | VMBPSUMNGR-20 — power supply manager: PSU load percentages, live wattage/voltage/amperage per rail, a warranty (hours-in-operation) counter, and PSU/warranty alarm status |
|
|
300
316
|
|
|
301
317
|
Palette group colours: **Velbus (inputs)** is teal (`#3A8C8C`), **Velbus (outputs)** is
|
|
@@ -331,23 +347,31 @@ blue (`#4A90D9`).
|
|
|
331
347
|
| 0x2F | VMBDMI-R | velbus-dimmer | n/a |
|
|
332
348
|
| 0x4B | VMB8DC-20 | velbus-dimmer-20 | n/a |
|
|
333
349
|
|
|
334
|
-
### Push buttons
|
|
335
|
-
| Type byte | Module |
|
|
336
|
-
|
|
337
|
-
| 0x01 | VMB8PB |
|
|
338
|
-
| 0x16 | VMB8PBU |
|
|
339
|
-
| 0x17 | VMB6PBN |
|
|
340
|
-
| 0x18 | VMB2PBN |
|
|
341
|
-
| 0x44 | VMB4PB | velbus-button |
|
|
342
|
-
| 0x4C | VMB6PB-20 | velbus-
|
|
343
|
-
|
|
344
|
-
|
|
350
|
+
### Push buttons (all → velbus-button, 12 types)
|
|
351
|
+
| Type byte | Module | Lock/unlock | Notes |
|
|
352
|
+
|---|---|---|---|
|
|
353
|
+
| 0x01 | VMB8PB | No | Simpler 0xED (LED status only), no lock command at all |
|
|
354
|
+
| 0x16 | VMB8PBU | Yes | |
|
|
355
|
+
| 0x17 | VMB6PBN | Yes | |
|
|
356
|
+
| 0x18 | VMB2PBN | — | Not yet cross-checked for lock support, treated conservatively |
|
|
357
|
+
| 0x44 | VMB4PB | Yes | **Type byte corrected 09/07/2026** — was wrongly keyed 0x1C in `velbus-button.js`'s own registry (not a real type byte at all); `velbus-scan.js` always had 0x44 right |
|
|
358
|
+
| 0x4C | VMB6PB-20 | Yes | **Type byte corrected 09/07/2026** — was wrongly keyed 0x20 (which is actually VMBGP4, a different module); `velbus-scan.js` always had 0x4C right |
|
|
359
|
+
| 0x0A | VMB8IR | No | IR receiver — presents fixed Velbus IR codes as button events |
|
|
360
|
+
| 0x0B | VMB4PD | No | LCD module — only the 4 button channels covered, not the LCD |
|
|
361
|
+
| 0x1A | VMB4RF | Yes | 4 channels (matches its name) — status uses 0xB4, not 0xED, so rich status is not decoded even though lock/unlock works |
|
|
362
|
+
| 0x30 | VMBRFR8S | Yes | |
|
|
363
|
+
| 0x33 | VMBVP01 | No | DoorBird — fixed semantic labels (Motion 1/2, Bell 1/2, Door 1/2, Virtual button 1/2), different/shorter 0xED not decoded |
|
|
364
|
+
| 0x42 | VMBKP | Yes | |
|
|
365
|
+
| 0x43 | VMBIN | Yes | Single channel |
|
|
366
|
+
|
|
367
|
+
### Glass panels (all → velbus-glass-panel, 29 types)
|
|
345
368
|
| Type byte | Module | OLED | PIR | Open collector | Min. map version |
|
|
346
369
|
|---|---|---|---|---|---|
|
|
347
370
|
| 0x1E | VMBGP1 | no | no | unconfirmed¹ | — |
|
|
348
371
|
| 0x1F | VMBGP2 | no | no | unconfirmed¹ | — |
|
|
349
372
|
| 0x20 | VMBGP4 | no | no | unconfirmed¹ | — |
|
|
350
373
|
| 0x21 | VMBGPO | yes | no | yes | 2 |
|
|
374
|
+
| 0x25 | VMBGPTC | yes | no | no | — |
|
|
351
375
|
| 0x28 | VMBGPOD | yes | no | no | — |
|
|
352
376
|
| 0x2D | VMBGP4PIR | no | yes | unconfirmed¹ | — |
|
|
353
377
|
| 0x34 | VMBEL1 | no | no | yes | 2 |
|
|
@@ -359,6 +383,7 @@ blue (`#4A90D9`).
|
|
|
359
383
|
| 0x3B | VMBGP2-2 | no | no | no² | — |
|
|
360
384
|
| 0x3C | VMBGP4-2 | no | no | no² | — |
|
|
361
385
|
| 0x3D | VMBGPOD-2 | yes | no | unconfirmed¹ | 2 |
|
|
386
|
+
| 0x3E | VMBGP4PIR-2 | no | yes | unconfirmed¹ | — |
|
|
362
387
|
| 0x47 | VMBEL2PIR | no | yes | yes | — |
|
|
363
388
|
| 0x4F | VMBEL1-20 | no | no | yes | — |
|
|
364
389
|
| 0x50 | VMBEL2-20 | no | no | yes | — |
|
|
@@ -372,6 +397,14 @@ blue (`#4A90D9`).
|
|
|
372
397
|
| 0x5C | VMBEL2PIR-20³ | no | yes | yes | — |
|
|
373
398
|
| 0x5F | VMBGP4PIR-20 | no | yes | unconfirmed¹ | — |
|
|
374
399
|
|
|
400
|
+
⁴ VMBGPTC (0x25) shares its actual protocol document with VMBGPO (0x21) — a
|
|
401
|
+
thermostat-only variant of the same touch panel hardware, not a separate
|
|
402
|
+
product. Type byte confirmed from the official type list, not spelled out
|
|
403
|
+
separately in the shared document's body. VMBGP4PIR-2 (0x3E) has genuinely
|
|
404
|
+
different channel 5-8 semantics from its 0x2D sibling despite the similar
|
|
405
|
+
name (Dark/Light output, Motion output, Light-depending-motion, Absence
|
|
406
|
+
output — not virtual/dark/light/motion) — confirmed directly, not assumed.
|
|
407
|
+
|
|
375
408
|
¹ Open-collector support unconfirmed against real hardware — see [section 13](#13-known-open-issues).
|
|
376
409
|
² Confirmed no open-collector commands in the protocol PDF, but not yet live-verified.
|
|
377
410
|
³ The official Velbus type list shows different module names at these two type bytes than
|
|
@@ -395,6 +428,7 @@ what this registry currently uses — flagged for verification, see
|
|
|
395
428
|
| 0x31 | VMBMETEO | velbus-meteo |
|
|
396
429
|
| 0x32 | VMB4AN | velbus-sensor |
|
|
397
430
|
| 0x4E | VMB8IN-20 | velbus-sensor-20 |
|
|
431
|
+
| 0x05 | VMB6IN | velbus-sensor — simpler sibling of VMB7IN, no lock/unlock at all, 5-byte 0xED (vs VMB7IN's 7) safely skipped by the existing length guard |
|
|
398
432
|
|
|
399
433
|
### Blind / shutter
|
|
400
434
|
| Type byte | Module | Node |
|
|
@@ -494,6 +528,36 @@ body[6] = error bitmask
|
|
|
494
528
|
body[7] = alarm/program byte
|
|
495
529
|
```
|
|
496
530
|
|
|
531
|
+
### 7.5a `0xB8` dimmer status — original series (VMBDMI, VMBDMI-R, VMB4DC)
|
|
532
|
+
|
|
533
|
+
**Not the same shape as 7.5 above, despite both being "dimmer status."**
|
|
534
|
+
Confirmed identical across all three original-series protocol PDFs — one
|
|
535
|
+
combined status byte, not separate mode/status bytes the way relay modules
|
|
536
|
+
or the V2 dimmer status have:
|
|
537
|
+
```
|
|
538
|
+
body[0] = 0xB8
|
|
539
|
+
body[1] = channel (VMBDMI/-R: always 0x01; VMB4DC: bitmask)
|
|
540
|
+
body[2] = status byte — MULTIPLE bit-fields packed together:
|
|
541
|
+
bits 0-1: run mode (00=normal, 01=inhibited, 10=forced_on, 11=disabled)
|
|
542
|
+
bits 2-3: error (VMBDMI/-R only — VMB4DC has no thermal section at all)
|
|
543
|
+
bit 4: load type (VMBDMI/-R only: 0=resistive, 1=inductive)
|
|
544
|
+
bits 5-7: temperature band (VMBDMI/-R only, 8 levels)
|
|
545
|
+
body[3] = dim value (0-100%)
|
|
546
|
+
body[4] = LED indicator status ONLY — unrelated to run state (0x00 off,
|
|
547
|
+
0x80 on, 0x40 slow blink, 0x20 fast blink, 0x10 very fast blink)
|
|
548
|
+
body[5-7] = 24-bit current delay time, MSB first
|
|
549
|
+
```
|
|
550
|
+
There is no separate `"forced_off"` status — that's a real, distinct
|
|
551
|
+
*command* (0x12) you can send, but the module reports its result through
|
|
552
|
+
the same four-value run-mode set above, same as relay's forced/inhibited
|
|
553
|
+
pattern conceptually, but packed into one byte here rather than two.
|
|
554
|
+
`on` is true for `forced_on`, or for `normal` mode with a nonzero dim
|
|
555
|
+
value — **not** simply "mode equals the literal string on," which was the
|
|
556
|
+
real bug (v0.10.1): a dimmer in ordinary normal-running mode — by far the
|
|
557
|
+
most common real-world state — was being read as `off` regardless of dim
|
|
558
|
+
level, because the code checked the LED status byte's low bits for
|
|
559
|
+
confirmation instead of using the dim value directly.
|
|
560
|
+
|
|
497
561
|
### 7.6 `0xA5` dim level — up to four channels packed per packet
|
|
498
562
|
```
|
|
499
563
|
body[0] = 0xA5, body[1] = channel, body[2] = level (0-254)
|
|
@@ -525,6 +589,23 @@ Address assignment: allow 500ms, then rescan to confirm the new address took eff
|
|
|
525
589
|
not the right trigger for an automatic write-back, both for the EEPROM-wear reason above
|
|
526
590
|
and because it risks a feedback loop. Reads have no such constraint and are always safe.
|
|
527
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
|
+
|
|
528
609
|
### 7.9 Thermostat commands — always to the primary address
|
|
529
610
|
```
|
|
530
611
|
0xDB = comfort mode, 0xDC = day mode, 0xDD = night mode, 0xDE = safe mode
|
|
@@ -621,7 +702,7 @@ about why in the commit message.
|
|
|
621
702
|
|
|
622
703
|
- **Generational split.** Nodes generally split at the V2.0 boundary — one node for
|
|
623
704
|
original-series, a separate node for V2. **Exceptions:** `velbus-glass-panel` (one
|
|
624
|
-
node covers all
|
|
705
|
+
node covers all 29 types, both generations, via the type registry's per-type flags
|
|
625
706
|
rather than a code-level split), `velbus-thermostat` (covers the thermostat function
|
|
626
707
|
on any glass panel type), `velbus-meteo` (only one generation exists), and the blind
|
|
627
708
|
family (`velbus-blind` / `velbus-blind-s` / `velbus-blind-20`, split by actual protocol
|
|
@@ -775,6 +856,25 @@ orientation at the time of writing:
|
|
|
775
856
|
|
|
776
857
|
- **Field-tested against live hardware:** the core relay, dimmer, glass panel, and
|
|
777
858
|
thermostat nodes have real-hardware confirmation for their primary functions.
|
|
859
|
+
`VMBGPOD` (0x28) specifically confirmed 09/07/2026 against two real panels on
|
|
860
|
+
Stuart's own home bus, closing out the v0.9.2/v0.9.3 registry-gap saga with an
|
|
861
|
+
actual result rather than just a passing test.
|
|
862
|
+
- **`velbus-dimmer`'s `0xB8` status decode was fundamentally wrong from when it was
|
|
863
|
+
first written until v0.10.1** — see section 7.5a. A dimmer in ordinary "normal
|
|
864
|
+
running" mode always reported `off` regardless of actual dim level. Fixed and
|
|
865
|
+
verified via the mock harness against the exact reported scenario, but not yet
|
|
866
|
+
re-confirmed against Stuart's real VMBDMI.
|
|
867
|
+
- **`velbus-glass-panel`'s `0xEA` thermostat status has been silently crashing
|
|
868
|
+
since it was written, until v0.10.1** — see section 16's code style rules for
|
|
869
|
+
the full story. The `type:"thermostat"` payload has likely never once been
|
|
870
|
+
successfully delivered for any real thermostat-equipped panel. Fixed and swept
|
|
871
|
+
for the same pattern elsewhere in the file (none found), but not yet
|
|
872
|
+
re-confirmed against Stuart's real hardware.
|
|
873
|
+
- **`velbus-button` had a critical, real bug from its first version until v0.9.4** —
|
|
874
|
+
see section 4.3 for the full story. Its press/release/long-press decode is now
|
|
875
|
+
fixed and verified with a real repro, but has not yet been re-confirmed against a
|
|
876
|
+
live button press on real hardware (only via the mock harness) — worth doing
|
|
877
|
+
before trusting it fully, given how long the broken version went unnoticed.
|
|
778
878
|
- **Mock-harness verified only, not yet confirmed against a real bus:** `velbus-clock`
|
|
779
879
|
(both the time/date/DST broadcast and the `set_alarm` command), the
|
|
780
880
|
`velbus-dimmer-20` `get_device_type` read command, and `velbus-energy` in its
|
|
@@ -790,9 +890,10 @@ orientation at the time of writing:
|
|
|
790
890
|
## 13. Known open issues
|
|
791
891
|
|
|
792
892
|
- **`VMBKP` (0x42, "Keypad interface module") has no node at all.** Found scanning a
|
|
793
|
-
real installation (Stuart's home)
|
|
794
|
-
module
|
|
795
|
-
|
|
893
|
+
real installation (Stuart's home) — confirmed present at address `0xFD`, a real
|
|
894
|
+
module on a real bus, not a hypothetical. A genuinely new module type, not yet
|
|
895
|
+
scoped. Its protocol PDF (`protocol_vmbkp.pdf`, 28 pages) is substantial: channel
|
|
896
|
+
status, module status, and a full per-channel LED control layer
|
|
796
897
|
(clear/set/slow-blink/fast-blink/very-fast-blink), similar in spirit to `velbus-button`
|
|
797
898
|
but with LED feedback control `velbus-button` doesn't have. This needs the same
|
|
798
899
|
"how much work would this involve" scoping pass `velbus-energy` got before it was
|
|
@@ -826,6 +927,33 @@ orientation at the time of writing:
|
|
|
826
927
|
against the year's January/July offsets to infer whether daylight saving is active)
|
|
827
928
|
has only been sanity-checked in an environment where daylight saving never applies —
|
|
828
929
|
a genuine positive "DST is active" case hasn't been observed and confirmed correct.
|
|
930
|
+
- **`VMB1DM`, `VMBDME`, `VMB1LED` (dimmer-family additions) deferred, not built.**
|
|
931
|
+
All three use a genuinely different single-channel `0xEE` status layout
|
|
932
|
+
(mode/dim-value/LED/timer/config in one packet) — distinct from both
|
|
933
|
+
`velbus-dimmer`'s own `0xB8`-based format and `velbus-dimmer-20`'s
|
|
934
|
+
multi-channel bitmask `0xEE` format. Needs real new decode logic, not a
|
|
935
|
+
registry entry — see `coverage-roadmap.md` for the full reasoning.
|
|
936
|
+
- **Bus error counter (`0xDA`) — design settled, not built.** Confirmed
|
|
937
|
+
useful but explicitly framed as a rare edge case. Resolved design: every
|
|
938
|
+
node that registers for its own address already receives an unsolicited
|
|
939
|
+
`0xDA` broadcast if one occurs, so no new request command is needed —
|
|
940
|
+
just passive decoding, emitted only on a secondary output and only when
|
|
941
|
+
at least one counter is non-zero, so it never appears during normal
|
|
942
|
+
operation. Deliberately deferred since it touches most/all existing nodes
|
|
943
|
+
— a session of its own, not a quick addition.
|
|
944
|
+
- **OLED image writing — stretch goal, not built.** Pushing a custom B&W
|
|
945
|
+
1-bit bitmap to an OLED glass panel (e.g. swapping in a different-language
|
|
946
|
+
greeting for a visitor without opening VelbusLink) — genuine use case,
|
|
947
|
+
explicitly not urgent. `velbus-glass-panel` currently only reads memo text
|
|
948
|
+
(`0xAC`), no write path exists in either direction for display content.
|
|
949
|
+
- **`VMBDALI`/`VMBDALI-20`, `VMBLCDWB`, `VMCM3`, `VMBSIG`/`VMBSIG-20`/`VMBSIG-21`
|
|
950
|
+
— recognized, deliberately not supported.** These show their correct name
|
|
951
|
+
in a scan (not `unknown_0xNN`) with an explicit `"Not supported"` in place
|
|
952
|
+
of a suggested node, rather than silently falling through to `null`. DALI
|
|
953
|
+
is its own protocol layer beyond the gateway; the Signum types are a
|
|
954
|
+
proprietary HomeAssistant-based master clock, not interactable; VMBLCDWB
|
|
955
|
+
and VMCM3 are legacy/custom modules with no planned support. By design,
|
|
956
|
+
not oversight — see `coverage-roadmap.md` for the full per-type reasoning.
|
|
829
957
|
|
|
830
958
|
---
|
|
831
959
|
|
|
@@ -916,6 +1044,49 @@ git push --tags
|
|
|
916
1044
|
that node's own `.html` dropdown copy, and `velbus-scan.js`'s independent copy) —
|
|
917
1045
|
see section 3 for the full explanation. Missing one produces a symptom in a
|
|
918
1046
|
different part of the palette than wherever the type was actually added.
|
|
1047
|
+
- **Never assume a feature is universal across a module family — check each type's
|
|
1048
|
+
own protocol document.** Proven wrong repeatedly (09/07/2026) while adding
|
|
1049
|
+
lock/unlock and richer status decode to `velbus-button`: of 12 button-family
|
|
1050
|
+
types, 4 genuinely lack the lock/unlock command entirely (not "probably most
|
|
1051
|
+
don't" — specific, named exceptions); one type's status uses a completely
|
|
1052
|
+
different command byte (`0xB4` instead of `0xED`); the "which channel" selector
|
|
1053
|
+
byte in the name-request commands uses two incompatible conventions (bitmask vs.
|
|
1054
|
+
literal number) that happen to produce identical values for channels 1-2 and only
|
|
1055
|
+
diverge from channel 3 onward — exactly the kind of divergence that survives
|
|
1056
|
+
casual testing. When a person asks for a capability "because it's a key feature,"
|
|
1057
|
+
that's a reason to verify it broadly, not a reason to skip checking each type.
|
|
1058
|
+
- **Registry type-byte keys need the same verification as everything else** — don't
|
|
1059
|
+
assume an existing entry's key is correct just because it's already shipped.
|
|
1060
|
+
Found 09/07/2026: `VMB4PB` and `VMB6PB-20` had been keyed under wrong type bytes
|
|
1061
|
+
in `velbus-button.js`'s own registry since v0.5.2 (`0x1C`, which isn't a real
|
|
1062
|
+
Velbus type byte at all, and `0x20`, which actually belongs to `VMBGP4`) — while
|
|
1063
|
+
`velbus-scan.js` had always had the correct values. Cross-check against the
|
|
1064
|
+
official type list (section 15) periodically, not just when adding something new.
|
|
1065
|
+
- **Never reference a variable that was only ever assigned as an object property.**
|
|
1066
|
+
Real bug, live since the code was written (fixed v0.10.1): `velbus-glass-panel`'s
|
|
1067
|
+
`0xEA` handler built `currentTemp`/`targetTemp` only inside a `payload = {...}`
|
|
1068
|
+
object literal, then referenced them as bare identifiers on the very next line
|
|
1069
|
+
(`setStatus('...' + currentTemp.toFixed(1) + ...)`). Since JS evaluates a
|
|
1070
|
+
function's arguments before calling it, this threw a `ReferenceError` *before*
|
|
1071
|
+
`node.send()` on the following line — meaning the entire payload silently never
|
|
1072
|
+
went out, for as long as this code existed. The bridge's own dispatch-error
|
|
1073
|
+
handling caught the exception each time rather than crashing the process, which
|
|
1074
|
+
is exactly what let this go unnoticed rather than being immediately obvious.
|
|
1075
|
+
If a value is going into both a status/log string and a payload object, declare
|
|
1076
|
+
it as its own `const` first and use that name in both places — never build it
|
|
1077
|
+
only inside the object literal and assume you can reference it by name outside.
|
|
1078
|
+
- **Don't assume a "two-byte status" pattern applies to every module family.**
|
|
1079
|
+
Real bug, live since the code was written (fixed v0.10.1): the original-series
|
|
1080
|
+
dimmer's `0xB8` status was assumed to work like relay's genuine separate
|
|
1081
|
+
mode-byte + status-byte pair. In reality `VMBDMI`/`VMBDMI-R`/`VMB4DC` pack
|
|
1082
|
+
run-mode, error, load-type, and temperature into a *single* status byte
|
|
1083
|
+
(confirmed identical across all three protocol PDFs — see section 7.5a), and
|
|
1084
|
+
the code was additionally reading the LED indicator byte as if it were a second
|
|
1085
|
+
status word. The result: a dimmer in ordinary "normal running" mode — the most
|
|
1086
|
+
common real-world state — always reported `off` regardless of actual dim level.
|
|
1087
|
+
Same underlying lesson as the button-family capability work: check each
|
|
1088
|
+
module's own protocol document for its actual byte layout, don't port a pattern
|
|
1089
|
+
from a different (even superficially similar) module family.
|
|
919
1090
|
- **Thermostat commands go to the primary address only,** never a subaddress.
|
|
920
1091
|
- **Respect the 20ms minimum between `0xFC` writes** on original-series modules — this
|
|
921
1092
|
is real EEPROM wear, not an arbitrary rate limit.
|
package/lib/glass-panel-types.js
CHANGED
|
@@ -61,6 +61,24 @@ const GLASS_PANEL_TYPES = {
|
|
|
61
61
|
minMapVer: 2,
|
|
62
62
|
series: 'original',
|
|
63
63
|
},
|
|
64
|
+
0x25: {
|
|
65
|
+
// Added 09/07/2026. Shares its actual protocol document with VMBGPO
|
|
66
|
+
// (protocol_vmbgpo_vmbgptc.pdf) — a thermostat-only variant of the same
|
|
67
|
+
// touch panel hardware, not a separate product. Type byte 0x25 confirmed
|
|
68
|
+
// from the official Velbus type list, not spelled out separately in the
|
|
69
|
+
// body of the shared document (it only gives VMBGPO's H'21' as a worked
|
|
70
|
+
// example). hasOc set conservatively to false — the shared document has
|
|
71
|
+
// no "collector" mention at all for either variant, unlike whatever
|
|
72
|
+
// source justified VMBGPO's own hasOc:true above (a different document,
|
|
73
|
+
// not re-verified here — that entry is untouched).
|
|
74
|
+
name: 'VMBGPTC',
|
|
75
|
+
channels: 32,
|
|
76
|
+
hasOled: true,
|
|
77
|
+
hasPir: false,
|
|
78
|
+
hasOc: false,
|
|
79
|
+
minMapVer: null,
|
|
80
|
+
series: 'original',
|
|
81
|
+
},
|
|
64
82
|
0x28: {
|
|
65
83
|
name: 'VMBGPOD',
|
|
66
84
|
// Added 09/07/2026 — found as "unknown_0x28" scanning a real installation.
|
|
@@ -98,6 +116,24 @@ const GLASS_PANEL_TYPES = {
|
|
|
98
116
|
minMapVer: null,
|
|
99
117
|
series: 'original',
|
|
100
118
|
},
|
|
119
|
+
0x3E: {
|
|
120
|
+
// Added 09/07/2026. IMPORTANT: this is NOT the same channel 5-8 mapping
|
|
121
|
+
// as its 0x2D sibling above, despite the similar name — confirmed
|
|
122
|
+
// directly from protocol_vmbgp4pir_ed2.pdf, which gives an entirely
|
|
123
|
+
// different set of labels. Copying the 0x2D mapping here would have
|
|
124
|
+
// silently mislabeled four channels.
|
|
125
|
+
name: 'VMBGP4PIR-2',
|
|
126
|
+
channels: 8,
|
|
127
|
+
hasOled: false,
|
|
128
|
+
hasPir: true,
|
|
129
|
+
hasOc: null, // no mention found in this PDF either — same unconfirmed state as 0x2D
|
|
130
|
+
pirChannels: {
|
|
131
|
+
1: 'button1', 2: 'button2', 3: 'button3', 4: 'button4',
|
|
132
|
+
5: 'dark_light', 6: 'motion', 7: 'light_motion', 8: 'absence',
|
|
133
|
+
},
|
|
134
|
+
minMapVer: null,
|
|
135
|
+
series: 'original',
|
|
136
|
+
},
|
|
101
137
|
0x34: {
|
|
102
138
|
name: 'VMBEL1',
|
|
103
139
|
channels: 1,
|