node-red-contrib-velbus-2026 0.10.1 → 0.10.3
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 +92 -0
- package/HANDOVER.md +59 -12
- package/coverage-roadmap.md +186 -0
- package/lib/glass-panel-types.js +12 -0
- package/nodes/velbus-glass-panel/velbus-glass-panel.html +50 -0
- package/nodes/velbus-glass-panel/velbus-glass-panel.js +72 -0
- package/nodes/velbus-sensor/velbus-sensor.html +17 -1
- package/nodes/velbus-sensor/velbus-sensor.js +47 -0
- package/package.json +1 -1
- package/velbus-2026-repo.bundle +0 -0
package/CHANGELOG_FORUM.md
CHANGED
|
@@ -29,6 +29,98 @@ separate duplicate-table bugs took to fully resolve.
|
|
|
29
29
|
|
|
30
30
|
---
|
|
31
31
|
|
|
32
|
+
## v0.10.3 — 09/07/2026
|
|
33
|
+
|
|
34
|
+
### velbus-glass-panel — VMBEL edge colour control (set_edge_color)
|
|
35
|
+
|
|
36
|
+
- **Prompted by Stuart asking whether edge LED colours on `VMBEL` panels
|
|
37
|
+
could be controlled, or whether a raw-packet escape-hatch node (like the
|
|
38
|
+
original palette had) was needed instead.** Confirmed a real, well-defined
|
|
39
|
+
live-bus command exists — no raw-packet node needed for this case.
|
|
40
|
+
- **Scope deliberately split, per explicit decision:** `COMMAND_SET_PB_
|
|
41
|
+
BACKLIGHT` (`0xD4`) covers two different operations distinguished only by
|
|
42
|
+
DLC — "Set Custom Color" (`DLC=6`, *defines* a custom RGB palette slot)
|
|
43
|
+
and "Set Edge Color" (`DLC=4`, *applies* an already-defined colour).
|
|
44
|
+
Only the latter is implemented: defining new custom colours is
|
|
45
|
+
commissioning-time configuration, staying in VelbusLink's domain, same
|
|
46
|
+
reasoning as `VMB4LEDPWM-20`'s grouping mode and Program Step read/write
|
|
47
|
+
elsewhere in this project. See `HANDOVER.md` section 7.8b for the full
|
|
48
|
+
byte layout.
|
|
49
|
+
- **`hasEdgeLed` gated to the confirmed `VMBEL` family only** (12 of 29
|
|
50
|
+
glass panel types: `VMBEL1/2/4`, `VMBELO`, `VMBELPIR`, `VMBEL2PIR`, and
|
|
51
|
+
their `-20` siblings) — `VMBGP`-family panels have only a single-colour
|
|
52
|
+
front LED per button, genuinely different hardware, not just a missing
|
|
53
|
+
feature. Verified the command is byte-for-byte identical across every
|
|
54
|
+
`VMBEL` sub-family protocol PDF before implementing once. One vestigial
|
|
55
|
+
"Edge color inhibited" status bit found in `VMBGP1-20/2-20/4-20`'s own
|
|
56
|
+
`0xED` — confirmed as inherited documentation cruft, not evidence of real
|
|
57
|
+
edge-colour hardware on those panels.
|
|
58
|
+
- New `set_edge_color` command: `layers` (background/continuous/slow_blink/
|
|
59
|
+
fast_blink, any combination), `edges` (left/top/right/bottom, any
|
|
60
|
+
combination), `page` (1-8 or "all"), `palette` (default/custom), `index`
|
|
61
|
+
(0-31), `priority` (custom only), `blink`. Sending to a non-`VMBEL` panel
|
|
62
|
+
warns clearly and sends nothing, matching the established per-type
|
|
63
|
+
gating pattern used throughout this palette.
|
|
64
|
+
- Housekeeping: removed a stale "`VMBKP` has no node at all" entry from
|
|
65
|
+
`HANDOVER.md`'s known-open-issues — that was resolved back in v0.10.0
|
|
66
|
+
when `VMBKP` was folded into `velbus-button`, but the issue list was
|
|
67
|
+
never updated to reflect it.
|
|
68
|
+
|
|
69
|
+
Verified via the mock-RED harness: default palette, custom palette with
|
|
70
|
+
priority and blink flag, all-defaults shorthand, and rejection on a
|
|
71
|
+
non-`VMBEL` type — every case with hand-checked checksums and manually
|
|
72
|
+
verified bitfield encoding, not just visual review. Not yet sent to a real
|
|
73
|
+
bus.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## v0.10.2 — 09/07/2026
|
|
78
|
+
|
|
79
|
+
### velbus-sensor — VMB4AN generic analogue reading (channels 9-12)
|
|
80
|
+
|
|
81
|
+
- **Prompted by Stuart noticing `isVMB4AN` was defined but never used** —
|
|
82
|
+
confirmed the sensor-input channels (Group 2 of VMB4AN's three functional
|
|
83
|
+
groups) produced literally no output at all beforehand; the packet
|
|
84
|
+
carrying that data wasn't handled anywhere in the file.
|
|
85
|
+
- **Real trap found and avoided:** the obviously-named `0xEA`
|
|
86
|
+
("sensor status") packet does **not** carry a value at all — it's
|
|
87
|
+
operating-mode/sleep-timer/auto-send configuration only. The actual
|
|
88
|
+
reading lives in a separate, easy-to-miss packet earlier in the protocol
|
|
89
|
+
document: `0xA9` (`COMMAND_SENSOR_RAW_DATA`, "Transmit the sensor raw
|
|
90
|
+
value"), genuinely standalone with no need to cross-reference anything
|
|
91
|
+
else. Also confirmed `0xE8`/`0xE9` ("sensor settings") is preset
|
|
92
|
+
*configuration* storage, not a live value either — three different
|
|
93
|
+
packets that could each plausibly have been mistaken for "the reading."
|
|
94
|
+
- Deliberately generic, per explicit preference: emits `{ type: "analogue",
|
|
95
|
+
channel, mode, raw }` with no engineering-unit conversion attempted —
|
|
96
|
+
`mode` (voltage/current/resistance/period) and the PDF's resolution
|
|
97
|
+
table are exposed in the node's help so conversion can happen in the flow
|
|
98
|
+
instead.
|
|
99
|
+
- New `get_analogue` input command (`0xE5`, request-a-reading-now) — uses
|
|
100
|
+
the protocol's own "auto-send config byte = 0" option to request a value
|
|
101
|
+
without side-effecting the module's existing auto-send schedule.
|
|
102
|
+
**Priority byte corrected during verification:** the protocol PDF
|
|
103
|
+
explicitly states "SID10-SID9 = 11 (lowest priority)" for this specific
|
|
104
|
+
command — `0xFB`, not the `0xF8` most other commands in this file use.
|
|
105
|
+
Checked directly rather than assumed, since this is the one place it
|
|
106
|
+
genuinely differs from the file's established convention.
|
|
107
|
+
- Both confirmed absent from `VMB7IN`'s own protocol PDF before wiring
|
|
108
|
+
in — this file's switch statement handles both module types together,
|
|
109
|
+
so a collision would misfire for `VMB7IN` modules if either byte had
|
|
110
|
+
been reused there.
|
|
111
|
+
- **Full Group 2 configuration (presets, mode-switching, sleep time,
|
|
112
|
+
offset, auto-send interval config) and all of Group 3 (analog outputs)
|
|
113
|
+
remain parked** — see `coverage-roadmap.md` section 6. This is
|
|
114
|
+
deliberately just the minimal reading piece, not the full feature.
|
|
115
|
+
|
|
116
|
+
Verified via the mock-RED harness: voltage/period modes, both period
|
|
117
|
+
special-value cases (`0x000000` short-circuit, `0xFFFFFF` open-circuit),
|
|
118
|
+
`VMB7IN` isolation confirmed (same bytes produce no output on that type),
|
|
119
|
+
`get_analogue` checksum hand-verified, correctly rejected on non-VMB4AN
|
|
120
|
+
types. Not yet sent to a real bus.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
32
124
|
## v0.10.1 — 09/07/2026
|
|
33
125
|
|
|
34
126
|
### 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.
|
|
9
|
+
Current state at time of writing: **v0.10.3, 19 nodes, published on npm.**
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
@@ -300,13 +300,13 @@ or a string before assuming the parsing logic itself is wrong.
|
|
|
300
300
|
| `velbus-relay-20` | Velbus (outputs) | V2 relays: VMB1RYS-20, VMB4RYLD-20, VMB4RYNO-20 |
|
|
301
301
|
| `velbus-dimmer` | Velbus (outputs) | Original-series dimmers: VMBDMI, VMBDMI-R, VMB4DC |
|
|
302
302
|
| `velbus-dimmer-20` | Velbus (outputs) | V2 dimmers: VMB2DC-20, VMB8DC-20, VMB4LEDPWM-20 (incl. RGB/RGBW grouping mode) |
|
|
303
|
-
| `velbus-glass-panel` | Velbus (inputs) | All 29 glass panel types (original + V2), buttons/OLED/PIR/open-collector as applicable per type |
|
|
303
|
+
| `velbus-glass-panel` | Velbus (inputs) | All 29 glass panel types (original + V2), buttons/OLED/PIR/open-collector as applicable per type. `VMBEL` family only (12 of the 29 types): `set_edge_color` applies an already-defined colour across layer/edge/page combinations — deliberately not palette *definition*, which stays in VelbusLink |
|
|
304
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 |
|
|
305
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) |
|
|
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,62 @@ 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
|
+
|
|
609
|
+
### 7.8b `0xD4` — one command byte, two very different operations, `VMBEL` family only
|
|
610
|
+
|
|
611
|
+
`COMMAND_SET_PB_BACKLIGHT` (`0xD4`) covers **two genuinely different commands**,
|
|
612
|
+
distinguished only by `DLC` (data length), confirmed identical across every
|
|
613
|
+
`VMBEL` sub-family protocol PDF checked (`VMBEL1/2/4`, `VMBELO`, `VMBELPIR`,
|
|
614
|
+
and their `-20` siblings):
|
|
615
|
+
|
|
616
|
+
- **"Set Custom Color" (`DLC=6`)** — *defines* one of 32 custom colour
|
|
617
|
+
palette slots as an actual RGB (or white+saturation) value:
|
|
618
|
+
`[0xD4, paletteIndex(0-31), rgbOrWhiteFlag+saturation, red, green, blue]`.
|
|
619
|
+
**Deliberately not implemented** — defining new custom colours is
|
|
620
|
+
commissioning-time configuration, and per an explicit decision, stays in
|
|
621
|
+
VelbusLink's domain. Same reasoning as `VMB4LEDPWM-20`'s grouping mode and
|
|
622
|
+
Program Step read/write elsewhere in this project.
|
|
623
|
+
- **"Set Edge Color" (`DLC=4`)** — *applies* an already-defined colour
|
|
624
|
+
(default palette, or a custom slot VelbusLink has already programmed)
|
|
625
|
+
across a chosen combination of layer/edge/page. This one **is**
|
|
626
|
+
implemented (`velbus-glass-panel`'s `set_edge_color` command) — a
|
|
627
|
+
genuine live/runtime action, not palette editing:
|
|
628
|
+
```
|
|
629
|
+
body[0] = 0xD4
|
|
630
|
+
body[1] = layer bitmask (bit0=background, bit1=continuous-feedback,
|
|
631
|
+
bit2=slow-blink-feedback, bit3=fast-blink-feedback) + bit7
|
|
632
|
+
(0=default palette, 1=custom palette)
|
|
633
|
+
body[2] = edge bitmask (bit0=left, bit1=top, bit2=right, bit3=bottom) +
|
|
634
|
+
page nibble (bits4-7: 0-7=pages 1-8, 8-15=all pages — the
|
|
635
|
+
protocol PDF states the entire 1000-1111 range means "all",
|
|
636
|
+
not just one value)
|
|
637
|
+
body[3] = blink flag (bit7) + priority (bits5-6, custom palette only:
|
|
638
|
+
01=low, 10=mid, 11=high) + palette index (bits0-4, 0-31)
|
|
639
|
+
```
|
|
640
|
+
**Gated to `hasEdgeLed` types only** — the `VMBEL` family, confirmed
|
|
641
|
+
`VMBGP`-family panels genuinely lack this (they have a single-colour
|
|
642
|
+
front LED per button, not side-firing edge lighting — a real hardware
|
|
643
|
+
difference, not just a missing feature). One vestigial "Edge color
|
|
644
|
+
inhibited" status *bit* appears in `VMBGP1-20/2-20/4-20`'s `0xED` module
|
|
645
|
+
status — almost certainly inherited from shared documentation with the
|
|
646
|
+
`VMBEL` family, not evidence those panels have real edge-colour hardware.
|
|
647
|
+
|
|
592
648
|
### 7.9 Thermostat commands — always to the primary address
|
|
593
649
|
```
|
|
594
650
|
0xDB = comfort mode, 0xDC = day mode, 0xDD = night mode, 0xDE = safe mode
|
|
@@ -872,15 +928,6 @@ orientation at the time of writing:
|
|
|
872
928
|
|
|
873
929
|
## 13. Known open issues
|
|
874
930
|
|
|
875
|
-
- **`VMBKP` (0x42, "Keypad interface module") has no node at all.** Found scanning a
|
|
876
|
-
real installation (Stuart's home) — confirmed present at address `0xFD`, a real
|
|
877
|
-
module on a real bus, not a hypothetical. A genuinely new module type, not yet
|
|
878
|
-
scoped. Its protocol PDF (`protocol_vmbkp.pdf`, 28 pages) is substantial: channel
|
|
879
|
-
status, module status, and a full per-channel LED control layer
|
|
880
|
-
(clear/set/slow-blink/fast-blink/very-fast-blink), similar in spirit to `velbus-button`
|
|
881
|
-
but with LED feedback control `velbus-button` doesn't have. This needs the same
|
|
882
|
-
"how much work would this involve" scoping pass `velbus-energy` got before it was
|
|
883
|
-
built, not a quick bolt-on to an existing node.
|
|
884
931
|
- **Open-collector support** on several glass panel types (marked "unconfirmed" in the
|
|
885
932
|
registry in section 6) has not been verified against real hardware — the protocol PDFs
|
|
886
933
|
are ambiguous or silent on some of these. Sending `0x01`/`0x02`/`0x03` open-collector
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# Coverage Roadmap — Rationalized 09/July/2026
|
|
2
|
+
|
|
3
|
+
**STATUS: Implemented in v0.10.0 (09/July/2026).** Everything marked "confirmed
|
|
4
|
+
and ready to build" below has been built, tested, and shipped — including
|
|
5
|
+
the type-byte fixes and real protocol divergences caught along the way (see
|
|
6
|
+
`CHANGELOG_FORUM.md` v0.10.0 for the full list). The two genuinely deferred
|
|
7
|
+
items (dimmer family, bus error counter) and the OLED stretch goal are now
|
|
8
|
+
tracked directly in `HANDOVER.md` section 13 going forward — this document
|
|
9
|
+
remains as the record of the original rationalization discussion, not the
|
|
10
|
+
place to look for current status.
|
|
11
|
+
|
|
12
|
+
Synthesized from a full pass over every Velbus module type and feature not yet
|
|
13
|
+
covered by this palette. Organized by what actually needs to happen, not by the
|
|
14
|
+
order it came up in discussion.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 1. New types to add to existing nodes' registries
|
|
19
|
+
|
|
20
|
+
No new nodes required — each of these is a straightforward registry addition
|
|
21
|
+
to a node that already exists and already handles this exact command family.
|
|
22
|
+
|
|
23
|
+
| Type | Module | Target node | Note |
|
|
24
|
+
|---|---|---|---|
|
|
25
|
+
| 0x07 | VMB1DM | `velbus-dimmer` | Old, likely rare in the field, minimal effort |
|
|
26
|
+
| 0x14 | VMBDME | `velbus-dimmer` | |
|
|
27
|
+
| 0x0F | VMB1LED | `velbus-dimmer` | Confirmed via protocol PDF: "PWM LED strip dimmer module" — genuinely dimmer-family, not a separate concept |
|
|
28
|
+
| 0x0A | VMB8IR | `velbus-button` | Confirmed — just a button-event module |
|
|
29
|
+
| 0x0B | VMB4PD | `velbus-button` | Reclassified from "not supported" — confirmed as a 4-button interface |
|
|
30
|
+
| 0x1A | VMB4RF | `velbus-button` | Presents 8 button events to the bus, nothing more |
|
|
31
|
+
| 0x30 | VMBRFR8S | `velbus-button` | Same mechanism as VMB4RF |
|
|
32
|
+
| 0x33 | VMBVP01 | `velbus-button` | DoorBird video intercom OEM module — 8 button events |
|
|
33
|
+
| 0x42 | VMBKP | `velbus-button` | Already agreed — plus lock/unlock and richer status decode (section 3) |
|
|
34
|
+
| 0x43 | VMBIN | `velbus-button` | Single-channel input, EOL but real installed base |
|
|
35
|
+
| 0x05 | VMB6IN | `velbus-sensor` | Sibling of VMB7IN |
|
|
36
|
+
| 0x3E | VMBGP4PIR-2 | `velbus-glass-panel` | Original-series-2 sibling of the -20 already covered |
|
|
37
|
+
| 0x25 | VMBGPTC | `velbus-glass-panel` | Confirmed — shares its actual protocol PDF with VMBGPO (0x21), genuine glass-panel sibling |
|
|
38
|
+
|
|
39
|
+
**Resolved — `VMB1TC`/`VMB1TS`: out of scope, not "super easy."** Checked the
|
|
40
|
+
actual protocol: `VMB1TC` has its own distinct command vocabulary ("Sensor
|
|
41
|
+
zone number," "sensor time statistics request," "lock/unlock sensor local
|
|
42
|
+
control") that doesn't overlay onto the existing `velbus-thermostat` decode —
|
|
43
|
+
this would be real new command handling, not a registry entry. Per the
|
|
44
|
+
stated condition, this stays out of scope. Nothing in Velbus is genuinely
|
|
45
|
+
wireless (confirmed) other than 433MHz/IR modules, which translate to the
|
|
46
|
+
bus rather than living on it — so no "W"-variant type IDs to separately track.
|
|
47
|
+
|
|
48
|
+
**Resolved — `VMBLCDWB` (0x13):** confirmed as a pre-glass-panel thermostat
|
|
49
|
+
controller (Velleman product page: 4-button control with LCD display, 32
|
|
50
|
+
functions, time/date backup). Out of scope, name-only in section 2.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 2. Scan-table "see it, don't support it" additions
|
|
55
|
+
|
|
56
|
+
Named correctly in a scan (not `unknown_0xNN`), explicit "Not supported" note
|
|
57
|
+
in place of a suggested node — no live node built.
|
|
58
|
+
|
|
59
|
+
| Type | Module | Note |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| 0x45 / 0x5A | VMBDALI / VMBDALI-20 | Real prevalence (12 VLP projects) but DALI is its own protocol layer beyond the gateway — explicit "Not supported" label requested |
|
|
62
|
+
| 0x13 | VMBLCDWB | Pre-glass-panel thermostat controller (4-button + LCD + time/date backup) — confirmed out of scope, name only |
|
|
63
|
+
| 0x3F | VMCM3 | Custom corporate-client module, function unknown — name only |
|
|
64
|
+
| 0x39 / 0x5B / 0x60 | VMBSIG / VMBSIG-20 / VMBSIG-21 | Custom HomeAssistant-based master clock, not interactable — already named in the scanner; **worth aligning to the same explicit "Not supported" note style as VMBDALI for consistency**, rather than leaving these as a bare name with no note at all |
|
|
65
|
+
| 0x40 | VMBUSBIP | Already correctly handled as-is — no use in this context beyond potentially being what the bridge itself connects to |
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 3. Feature additions to existing nodes
|
|
70
|
+
|
|
71
|
+
- **`velbus-clock`: add sunrise/sunset enable/disable (`0xAE`)** — part of the
|
|
72
|
+
same shared system block as time/date/DST/alarm, genuinely missing.
|
|
73
|
+
- **`velbus-button`: lock/unlock (`0x12`/`0x13`) + richer `0xED` status decode**
|
|
74
|
+
(locked/enabled/inverted/program-selection) — already agreed, applies as a
|
|
75
|
+
general button-family capability, not scoped to VMBKP alone.
|
|
76
|
+
- **`velbus-button`: surface channel names in the event output** — using the
|
|
77
|
+
existing `0xF0`/`0xF1`/`0xF2` pattern, so named-channel modules (VMBKP, and
|
|
78
|
+
potentially others) show real names, not just channel numbers, while every
|
|
79
|
+
existing numbered-only setup keeps working unchanged.
|
|
80
|
+
|
|
81
|
+
- **Bus error counter (`0xDA`) — resolved design, scoped as a follow-up, not
|
|
82
|
+
built today.** Confirmed genuinely useful, but explicitly framed as an edge
|
|
83
|
+
case: "the once in a blue moon bus error message will clear itself within
|
|
84
|
+
a second or two — including it in normal payload traffic will cause
|
|
85
|
+
confusion." Resolved design: every node that registers for its own address
|
|
86
|
+
already receives every packet addressed to it, including an unsolicited
|
|
87
|
+
`0xDA` broadcast if one occurs — so no new "request" command is needed, just
|
|
88
|
+
passive decoding. Add `0xDA` handling to every existing node, emitting
|
|
89
|
+
**only on the secondary output** (never mixed into the main status payload
|
|
90
|
+
on output 1), and **only when at least one counter is non-zero** — silent
|
|
91
|
+
during normal operation, so it never appears unless there's genuinely
|
|
92
|
+
something to see. Nodes that currently only have a single output would need
|
|
93
|
+
a second one added. **Scoped as its own follow-up given it touches most or
|
|
94
|
+
all existing nodes — not part of today's build.**
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 4. Deferred — logged as a stretch goal, not being built now
|
|
99
|
+
|
|
100
|
+
- **OLED image writing** (pushing a custom B&W 1-bit bitmap to an OLED glass
|
|
101
|
+
panel) — genuine use case raised (swapping in a different-language greeting
|
|
102
|
+
for a visitor without opening VelbusLink). **Confirmed: no solid reason to
|
|
103
|
+
build it now** — parked in `HANDOVER.md` as an explicit stretch goal rather
|
|
104
|
+
than an open question.
|
|
105
|
+
|
|
106
|
+
**Resolved — calibration data:** no concrete current need. Stays out of
|
|
107
|
+
scope alongside generic memory read/write, parked for if/when a real need
|
|
108
|
+
comes up rather than built speculatively.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## 5. Confirmed out of scope — no action
|
|
113
|
+
|
|
114
|
+
- **Generic memory read/write** — the foundation Program Step would sit on;
|
|
115
|
+
out of scope as a consequence of Program Step being out of scope.
|
|
116
|
+
- **Program Step read/write** — explicitly parked pending VelbusLink's own
|
|
117
|
+
Delphi rewrite; a strong candidate to become its own separate project
|
|
118
|
+
rather than living in this palette at all.
|
|
119
|
+
- **Cross-module "linked" LED control** — out of scope.
|
|
120
|
+
- **IR learn-and-replay, reframed correctly:** this was mischaracterized in
|
|
121
|
+
the original list — it isn't third-party IR code learning at all. The
|
|
122
|
+
glass-panel IR variants simply respond to Velbus-defined HEX codes and
|
|
123
|
+
present them as button events (up to 32), with codes 33-39 specifically
|
|
124
|
+
translated into heating temperature mode changes that `velbus-thermostat`
|
|
125
|
+
would see. Genuinely out of scope as a project, but worth remembering this
|
|
126
|
+
detail if the IR-capable glass panel variants (`VMBGPOD_IR` etc.) ever get
|
|
127
|
+
addressed — the 33-39 range needs the same special handling as any other
|
|
128
|
+
thermostat mode change, not treatment as plain numbered buttons.
|
|
129
|
+
- **DALI bridging** — out of scope, name-only per section 2.
|
|
130
|
+
- **Signum integration** — out of scope, name-only per section 2.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## 6. VMB4AN — groups 2/3 parked, large commitment
|
|
135
|
+
|
|
136
|
+
**Status: parked 09/07/2026, not scoped for near-term work.** `velbus-sensor`
|
|
137
|
+
currently only implements Group 1 of VMB4AN's three functional groups (alarm
|
|
138
|
+
outputs, channels 1-8, via the standard `0x00` button-style event — the same
|
|
139
|
+
path VMB7IN uses). The `isVMB4AN` flag already in the code is a placeholder
|
|
140
|
+
that's never actually consumed anywhere.
|
|
141
|
+
|
|
142
|
+
- **Group 2 — sensor inputs (channels 9-12).** Each channel supports 4
|
|
143
|
+
configurable operating modes (voltage 0-10V / current 4-20mA / resistance
|
|
144
|
+
PT100-1000 / period measurement), 4 presets (safe/night/day/comfort — same
|
|
145
|
+
naming as thermostat presets), a sleep timer, and configurable auto-send
|
|
146
|
+
behaviour (fixed interval, or threshold-based at 3.125%/6.25%/12.5%/25%
|
|
147
|
+
change). Reading a value and reading full settings are two separate
|
|
148
|
+
packets (`0xEA` status, `0xE8`+`0xE9` two-part settings, confirmed from
|
|
149
|
+
`protocol_vmb4an.pdf`).
|
|
150
|
+
- **Group 3 — analog outputs (channels 13-16).** Effectively a full dimmer
|
|
151
|
+
control surface bolted onto VMB4AN — same command bytes as `velbus-dimmer`
|
|
152
|
+
itself (`0x07` set value, `0x11` restore last value), percentage or 12-bit
|
|
153
|
+
precision, timer/forced-on/inhibit, even reusing `0xB8` for its status
|
|
154
|
+
(same byte as `VMBDMI`'s dimmer status — no real conflict, different
|
|
155
|
+
module addresses, just worth knowing Velbus reuses this byte across
|
|
156
|
+
contexts). **Deprioritized further:** not yet configurable natively in
|
|
157
|
+
VelbusLink, so unlikely to appear in any real installation regardless of
|
|
158
|
+
whether this palette supports it — low priority until that changes.
|
|
159
|
+
- **Comparable in size to `velbus-energy`** — a genuine second build, not a
|
|
160
|
+
quick addition. Revisit if/when there's a concrete need.
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## 7. Final scope — everything below is confirmed and ready to build
|
|
165
|
+
|
|
166
|
+
**New registry entries** (sections 1 and 2 above) — 13 types added to
|
|
167
|
+
existing nodes' registries, 5 types added as scan-visible "not supported"
|
|
168
|
+
entries, no new nodes required for any of it.
|
|
169
|
+
|
|
170
|
+
**Feature additions to existing nodes:**
|
|
171
|
+
- `velbus-clock`: sunrise/sunset enable/disable (`0xAE`)
|
|
172
|
+
- `velbus-button`: lock/unlock (`0x12`/`0x13`), richer `0xED` status decode,
|
|
173
|
+
channel names surfaced in event output
|
|
174
|
+
|
|
175
|
+
**Explicitly deferred to a later session, design already settled:**
|
|
176
|
+
- Bus error counter (`0xDA`) — touches most/all existing nodes, scoped above
|
|
177
|
+
|
|
178
|
+
**Confirmed out of scope, no action ever:**
|
|
179
|
+
- Generic memory read/write, calibration data (no concrete need), Program
|
|
180
|
+
Step read/write, cross-module linked LED control, IR learn-and-replay (as
|
|
181
|
+
a feature — though see the 33-39 thermostat-mode detail above if the
|
|
182
|
+
IR-capable glass panel variants ever get addressed), DALI bridging, Signum
|
|
183
|
+
integration, `VMB1TC`/`VMB1TS` (genuinely not "easy"), `VMBLCDWB`.
|
|
184
|
+
|
|
185
|
+
**Logged as a stretch goal in `HANDOVER.md`, not built now:**
|
|
186
|
+
- OLED image writing
|
package/lib/glass-panel-types.js
CHANGED
|
@@ -140,6 +140,7 @@ const GLASS_PANEL_TYPES = {
|
|
|
140
140
|
hasOled: false,
|
|
141
141
|
hasPir: false,
|
|
142
142
|
hasOc: true, // Confirmed: VMBEL1/2/4 protocol PDF ed2 Nov 2024
|
|
143
|
+
hasEdgeLed: true, // VMBEL family confirmed - own protocol PDF has 'Set Edge Color' (0xD4)
|
|
143
144
|
minMapVer: 2,
|
|
144
145
|
series: 'original',
|
|
145
146
|
},
|
|
@@ -149,6 +150,7 @@ const GLASS_PANEL_TYPES = {
|
|
|
149
150
|
hasOled: false,
|
|
150
151
|
hasPir: false,
|
|
151
152
|
hasOc: true, // Confirmed: VMBEL1/2/4 protocol PDF ed2 Nov 2024
|
|
153
|
+
hasEdgeLed: true, // VMBEL family confirmed - own protocol PDF has 'Set Edge Color' (0xD4)
|
|
152
154
|
minMapVer: 2,
|
|
153
155
|
series: 'original',
|
|
154
156
|
},
|
|
@@ -158,6 +160,7 @@ const GLASS_PANEL_TYPES = {
|
|
|
158
160
|
hasOled: false,
|
|
159
161
|
hasPir: false,
|
|
160
162
|
hasOc: true, // Confirmed: VMBEL1/2/4 protocol PDF ed2 Nov 2024
|
|
163
|
+
hasEdgeLed: true, // VMBEL family confirmed - own protocol PDF has 'Set Edge Color' (0xD4)
|
|
161
164
|
minMapVer: 2,
|
|
162
165
|
series: 'original',
|
|
163
166
|
},
|
|
@@ -167,6 +170,7 @@ const GLASS_PANEL_TYPES = {
|
|
|
167
170
|
hasOled: true,
|
|
168
171
|
hasPir: false,
|
|
169
172
|
hasOc: true, // OLED/output variant — OC confirmed by protocol family
|
|
173
|
+
hasEdgeLed: true, // VMBEL family confirmed - own protocol PDF has 'Set Edge Color' (0xD4)
|
|
170
174
|
minMapVer: 4,
|
|
171
175
|
series: 'original',
|
|
172
176
|
},
|
|
@@ -176,6 +180,7 @@ const GLASS_PANEL_TYPES = {
|
|
|
176
180
|
hasOled: false,
|
|
177
181
|
hasPir: true,
|
|
178
182
|
hasOc: true, // PIR variant of VMBEL family — OC present
|
|
183
|
+
hasEdgeLed: true, // VMBEL family confirmed - own protocol PDF has 'Set Edge Color' (0xD4)
|
|
179
184
|
pirChannels: {
|
|
180
185
|
1: 'button1', 2: 'button2', 3: 'button3', 4: 'button4',
|
|
181
186
|
5: 'virtual', 6: 'dark', 7: 'light', 8: 'motion',
|
|
@@ -225,6 +230,7 @@ const GLASS_PANEL_TYPES = {
|
|
|
225
230
|
hasOled: false,
|
|
226
231
|
hasPir: true,
|
|
227
232
|
hasOc: true, // PIR variant of VMBEL family — OC present
|
|
233
|
+
hasEdgeLed: true, // VMBEL family confirmed - own protocol PDF has 'Set Edge Color' (0xD4)
|
|
228
234
|
pirChannels: {
|
|
229
235
|
1: 'button1', 2: 'button2',
|
|
230
236
|
3: 'virtual', 4: 'dark', 5: 'light', 6: 'motion',
|
|
@@ -241,6 +247,7 @@ const GLASS_PANEL_TYPES = {
|
|
|
241
247
|
hasOled: false,
|
|
242
248
|
hasPir: false,
|
|
243
249
|
hasOc: true, // Confirmed: VMBEL1/2/4 protocol PDF ed2 Nov 2024 covers -20 variants
|
|
250
|
+
hasEdgeLed: true, // VMBEL family confirmed - own protocol PDF has 'Set Edge Color' (0xD4)
|
|
244
251
|
minMapVer: null,
|
|
245
252
|
series: 'v2',
|
|
246
253
|
},
|
|
@@ -250,6 +257,7 @@ const GLASS_PANEL_TYPES = {
|
|
|
250
257
|
hasOled: false,
|
|
251
258
|
hasPir: false,
|
|
252
259
|
hasOc: true, // Confirmed: VMBEL1/2/4 protocol PDF ed2 Nov 2024 covers -20 variants
|
|
260
|
+
hasEdgeLed: true, // VMBEL family confirmed - own protocol PDF has 'Set Edge Color' (0xD4)
|
|
253
261
|
minMapVer: null,
|
|
254
262
|
series: 'v2',
|
|
255
263
|
},
|
|
@@ -259,6 +267,7 @@ const GLASS_PANEL_TYPES = {
|
|
|
259
267
|
hasOled: false,
|
|
260
268
|
hasPir: false,
|
|
261
269
|
hasOc: true, // Confirmed: VMBEL1/2/4 protocol PDF ed2 Nov 2024 covers -20 variants
|
|
270
|
+
hasEdgeLed: true, // VMBEL family confirmed - own protocol PDF has 'Set Edge Color' (0xD4)
|
|
262
271
|
minMapVer: null,
|
|
263
272
|
series: 'v2',
|
|
264
273
|
},
|
|
@@ -268,6 +277,7 @@ const GLASS_PANEL_TYPES = {
|
|
|
268
277
|
hasOled: true,
|
|
269
278
|
hasPir: false,
|
|
270
279
|
hasOc: true, // OLED/output variant — OC confirmed by protocol family
|
|
280
|
+
hasEdgeLed: true, // VMBEL family confirmed - own protocol PDF has 'Set Edge Color' (0xD4)
|
|
271
281
|
minMapVer: null,
|
|
272
282
|
series: 'v2',
|
|
273
283
|
},
|
|
@@ -277,6 +287,7 @@ const GLASS_PANEL_TYPES = {
|
|
|
277
287
|
hasOled: false,
|
|
278
288
|
hasPir: true,
|
|
279
289
|
hasOc: true, // PIR variant of VMBEL family — OC present
|
|
290
|
+
hasEdgeLed: true, // VMBEL family confirmed - own protocol PDF has 'Set Edge Color' (0xD4)
|
|
280
291
|
pirChannels: {
|
|
281
292
|
1: 'button1', 2: 'button2', 3: 'button3', 4: 'button4',
|
|
282
293
|
5: 'virtual', 6: 'dark', 7: 'light', 8: 'motion',
|
|
@@ -326,6 +337,7 @@ const GLASS_PANEL_TYPES = {
|
|
|
326
337
|
hasOled: false,
|
|
327
338
|
hasPir: true,
|
|
328
339
|
hasOc: true, // PIR variant of VMBEL family — OC present
|
|
340
|
+
hasEdgeLed: true, // VMBEL family confirmed - own protocol PDF has 'Set Edge Color' (0xD4)
|
|
329
341
|
pirChannels: {
|
|
330
342
|
1: 'button1', 2: 'button2',
|
|
331
343
|
3: 'virtual', 4: 'dark', 5: 'light', 6: 'motion',
|
|
@@ -316,6 +316,56 @@
|
|
|
316
316
|
<dt><code>{ "cmd": "led_set", "channel": 1 }</code></dt>
|
|
317
317
|
<dd>Control button LED. Commands: <code>led_set</code>, <code>led_clear</code>, <code>led_slow</code>, <code>led_fast</code>, <code>led_vfast</code>.</dd>
|
|
318
318
|
|
|
319
|
+
<dt><code>set_edge_color</code> — <strong>VMBEL family only</strong> (VMBEL1/2/4, VMBELO,
|
|
320
|
+
VMBELPIR, and their -20 siblings — not VMBGP-family panels, which have only a
|
|
321
|
+
single-colour front LED per button, not side-firing edge lighting)</dt>
|
|
322
|
+
<dd>
|
|
323
|
+
Applies an <em>already-defined</em> colour — the module's default palette, or a
|
|
324
|
+
custom slot VelbusLink has already programmed — across a chosen combination of
|
|
325
|
+
layer(s), edge(s), and button page. <strong>Does not define new custom colours</strong> —
|
|
326
|
+
that stays in VelbusLink; this node only ever applies/switches between colours that
|
|
327
|
+
already exist on the module.
|
|
328
|
+
<pre>
|
|
329
|
+
{ "cmd": "set_edge_color", "index": 5 }
|
|
330
|
+
// Simplest form — every field below is optional and defaults as shown.
|
|
331
|
+
// Applies default palette colour #5 to the background layer, all four
|
|
332
|
+
// edges, all button pages.
|
|
333
|
+
|
|
334
|
+
{ "cmd": "set_edge_color",
|
|
335
|
+
"layers": ["background", "continuous"],
|
|
336
|
+
"edges": ["left", "top", "right", "bottom"],
|
|
337
|
+
"page": 1,
|
|
338
|
+
"palette": "default",
|
|
339
|
+
"index": 5 }
|
|
340
|
+
// Same as above but explicit — background AND continuous-feedback layers,
|
|
341
|
+
// all edges, button page 1 only.
|
|
342
|
+
|
|
343
|
+
{ "cmd": "set_edge_color",
|
|
344
|
+
"layers": ["fast_blink"],
|
|
345
|
+
"edges": ["left"],
|
|
346
|
+
"page": "all",
|
|
347
|
+
"palette": "custom",
|
|
348
|
+
"index": 12,
|
|
349
|
+
"priority": "high",
|
|
350
|
+
"blink": true }
|
|
351
|
+
// Custom palette slot #12 (must already be programmed via VelbusLink),
|
|
352
|
+
// applied only to the fast-blink-feedback layer, left edge only, every
|
|
353
|
+
// button page, at highest override priority, with the blink flag set.
|
|
354
|
+
</pre>
|
|
355
|
+
<table style="width:100%; font-size:0.85em; border-collapse:collapse; margin-top:4px;">
|
|
356
|
+
<tr style="text-align:left; border-bottom:1px solid #ccc;"><th>Field</th><th>Values</th><th>Default if omitted</th></tr>
|
|
357
|
+
<tr><td><code>layers</code></td><td>array, any of: <code>background</code>, <code>continuous</code>, <code>slow_blink</code>, <code>fast_blink</code></td><td><code>["background"]</code></td></tr>
|
|
358
|
+
<tr><td><code>edges</code></td><td>array, any of: <code>left</code>, <code>top</code>, <code>right</code>, <code>bottom</code></td><td>all four</td></tr>
|
|
359
|
+
<tr><td><code>page</code></td><td><code>1</code>-<code>8</code>, or <code>"all"</code></td><td><code>"all"</code></td></tr>
|
|
360
|
+
<tr><td><code>palette</code></td><td><code>"default"</code> or <code>"custom"</code></td><td><code>"default"</code></td></tr>
|
|
361
|
+
<tr><td><code>index</code></td><td><code>0</code>-<code>31</code> (which palette slot to apply)</td><td><code>0</code></td></tr>
|
|
362
|
+
<tr><td><code>priority</code></td><td><code>"low"</code>/<code>"mid"</code>/<code>"high"</code> — <em>custom palette only</em>, ignored for default</td><td><code>"low"</code></td></tr>
|
|
363
|
+
<tr><td><code>blink</code></td><td><code>true</code>/<code>false</code></td><td><code>false</code></td></tr>
|
|
364
|
+
</table>
|
|
365
|
+
<p>Sending this to a non-VMBEL panel (e.g. VMBGP2) sends nothing and logs a clear
|
|
366
|
+
warning rather than silently failing.</p>
|
|
367
|
+
</dd>
|
|
368
|
+
|
|
319
369
|
<dt><code>{ "cmd": "output_on" }</code> / <code>"output_off"</code></dt>
|
|
320
370
|
<dd>Open collector output on/off.</dd>
|
|
321
371
|
|
|
@@ -38,6 +38,33 @@ const LED_CMD = {
|
|
|
38
38
|
led_vfast: 0xF9,
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
42
|
+
// Edge colour constants — VMBEL family only (hasEdgeLed), confirmed identical
|
|
43
|
+
// byte layout across every VMBEL sub-family protocol PDF checked (VMBEL1/2/4,
|
|
44
|
+
// VMBELO, VMBELPIR, and their -20 siblings). Command byte 0xD4
|
|
45
|
+
// (COMMAND_SET_PB_BACKLIGHT) is shared with 'Set Custom Color' (defining new
|
|
46
|
+
// custom RGB palette entries) — deliberately NOT implemented here. Defining
|
|
47
|
+
// custom colours is commissioning-time configuration and stays in
|
|
48
|
+
// VelbusLink's domain, same reasoning as VMB4LEDPWM-20's grouping mode and
|
|
49
|
+
// Program Step read/write elsewhere in this project. Only 'Set Edge Color'
|
|
50
|
+
// (applying an already-defined colour — default palette, or a custom slot
|
|
51
|
+
// VelbusLink has already programmed) is in scope: a genuine live/runtime
|
|
52
|
+
// action, not palette editing.
|
|
53
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
54
|
+
const EDGE_LAYER_BITS = {
|
|
55
|
+
background: 0x01,
|
|
56
|
+
continuous: 0x02,
|
|
57
|
+
slow_blink: 0x04,
|
|
58
|
+
fast_blink: 0x08,
|
|
59
|
+
};
|
|
60
|
+
const EDGE_SIDE_BITS = {
|
|
61
|
+
left: 0x01,
|
|
62
|
+
top: 0x02,
|
|
63
|
+
right: 0x04,
|
|
64
|
+
bottom: 0x08,
|
|
65
|
+
};
|
|
66
|
+
const EDGE_PRIORITY = { low: 0x01, mid: 0x02, high: 0x03 };
|
|
67
|
+
|
|
41
68
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
42
69
|
// Channel bitmask helpers
|
|
43
70
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -91,6 +118,7 @@ module.exports = function(RED) {
|
|
|
91
118
|
const typeDesc = (node.typeId !== null) ? (GLASS_PANEL_TYPES[node.typeId] || null) : null;
|
|
92
119
|
const hasOled = typeDesc ? typeDesc.hasOled : false;
|
|
93
120
|
const hasPir = typeDesc ? typeDesc.hasPir : false;
|
|
121
|
+
const hasEdgeLed = typeDesc ? !!typeDesc.hasEdgeLed : false;
|
|
94
122
|
const hasOc = typeDesc ? !!typeDesc.hasOc : false;
|
|
95
123
|
const pirCh = typeDesc ? (typeDesc.pirChannels || {}) : {};
|
|
96
124
|
|
|
@@ -421,6 +449,50 @@ module.exports = function(RED) {
|
|
|
421
449
|
return;
|
|
422
450
|
}
|
|
423
451
|
|
|
452
|
+
// ── Set edge colour (VMBEL family only) ─────────────────────────────
|
|
453
|
+
// Applies an already-defined colour (default palette, or a custom
|
|
454
|
+
// slot VelbusLink has already programmed) across a chosen combination
|
|
455
|
+
// of layer(s), edge(s), and button page. Does NOT define new custom
|
|
456
|
+
// colours — that stays in VelbusLink, see the constants comment above.
|
|
457
|
+
if (cmd === 'set_edge_color') {
|
|
458
|
+
if (!hasEdgeLed) {
|
|
459
|
+
node.warn('velbus-glass-panel: ' + (typeDesc ? typeDesc.name : 'this module type') +
|
|
460
|
+
' has no edge lighting (VMBEL family only) — sending nothing.');
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const layers = Array.isArray(msg.payload.layers) ? msg.payload.layers : ['background'];
|
|
465
|
+
const edges = Array.isArray(msg.payload.edges) ? msg.payload.edges : ['left', 'top', 'right', 'bottom'];
|
|
466
|
+
const palette = msg.payload.palette === 'custom' ? 'custom' : 'default';
|
|
467
|
+
const index = Math.max(0, Math.min(31, parseInt(msg.payload.index) || 0));
|
|
468
|
+
const blink = !!msg.payload.blink;
|
|
469
|
+
|
|
470
|
+
let db2 = 0;
|
|
471
|
+
for (const l of layers) db2 |= (EDGE_LAYER_BITS[l] || 0);
|
|
472
|
+
if (palette === 'custom') db2 |= 0x80;
|
|
473
|
+
|
|
474
|
+
let db3 = 0;
|
|
475
|
+
for (const e of edges) db3 |= (EDGE_SIDE_BITS[e] || 0);
|
|
476
|
+
// Page: 1-8 map to nibble 0-7; 'all' (or omitted) uses 0xF, matching
|
|
477
|
+
// the protocol's own stated range (1000xxxx through 1111xxxx all
|
|
478
|
+
// mean "all pages" — 0xF is simply the clearest, most explicit value
|
|
479
|
+
// in that range to use).
|
|
480
|
+
const page = msg.payload.page;
|
|
481
|
+
const pageNibble = (page === undefined || page === 'all')
|
|
482
|
+
? 0x0F
|
|
483
|
+
: Math.max(0, Math.min(7, parseInt(page) - 1));
|
|
484
|
+
db3 |= (pageNibble << 4) & 0xF0;
|
|
485
|
+
|
|
486
|
+
let db4 = index & 0x1F;
|
|
487
|
+
if (blink) db4 |= 0x80;
|
|
488
|
+
if (palette === 'custom') {
|
|
489
|
+
db4 |= (EDGE_PRIORITY[msg.payload.priority] || EDGE_PRIORITY.low) << 5;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
node.bridge.send(pkt(0xFB, node.address, [0xD4, db2, db3, db4]));
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
|
|
424
496
|
// ── Open collector output ──────────────────────────────────────────
|
|
425
497
|
if (cmd === 'output_on') {
|
|
426
498
|
// COMMAND_SWITCH_RELAY_ON (0x02), channel byte = don't care (0xFF)
|
|
@@ -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
|
|
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.
|
|
3
|
+
"version": "0.10.3",
|
|
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",
|
package/velbus-2026-repo.bundle
CHANGED
|
Binary file
|