node-red-contrib-velbus-2026 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG_FORUM.md +784 -0
- package/LICENSE +21 -0
- package/README.md +140 -0
- package/examples/velbus-basic-relay-dimmer.json +328 -0
- package/index.js +3 -0
- package/lib/blind-types-20.js +26 -0
- package/lib/blind-types-s.js +46 -0
- package/lib/blind-types.js +38 -0
- package/lib/dimmer-types-20.js +120 -0
- package/lib/dimmer-types.js +34 -0
- package/lib/glass-panel-types.js +296 -0
- package/lib/pir-types-20.js +51 -0
- package/lib/pir-types.js +61 -0
- package/lib/relay-types-20.js +43 -0
- package/lib/relay-types.js +39 -0
- package/lib/sensor-types-20.js +29 -0
- package/lib/sensor-types.js +49 -0
- package/lib/velbus-utils.js +80 -0
- package/nodes/velbus-blind/velbus-blind.html +165 -0
- package/nodes/velbus-blind/velbus-blind.js +251 -0
- package/nodes/velbus-blind-20/velbus-blind-20.html +179 -0
- package/nodes/velbus-blind-20/velbus-blind-20.js +300 -0
- package/nodes/velbus-blind-s/velbus-blind-s.html +181 -0
- package/nodes/velbus-blind-s/velbus-blind-s.js +282 -0
- package/nodes/velbus-bridge/velbus-bridge.html +72 -0
- package/nodes/velbus-bridge/velbus-bridge.js +304 -0
- package/nodes/velbus-button/velbus-button.html +172 -0
- package/nodes/velbus-button/velbus-button.js +117 -0
- package/nodes/velbus-clock/velbus-clock.html +198 -0
- package/nodes/velbus-clock/velbus-clock.js +273 -0
- package/nodes/velbus-dimmer/velbus-dimmer.html +174 -0
- package/nodes/velbus-dimmer/velbus-dimmer.js +457 -0
- package/nodes/velbus-dimmer-20/velbus-dimmer-20.html +271 -0
- package/nodes/velbus-dimmer-20/velbus-dimmer-20.js +602 -0
- package/nodes/velbus-glass-panel/velbus-glass-panel.html +337 -0
- package/nodes/velbus-glass-panel/velbus-glass-panel.js +492 -0
- package/nodes/velbus-meteo/velbus-meteo.html +120 -0
- package/nodes/velbus-meteo/velbus-meteo.js +279 -0
- package/nodes/velbus-pir/velbus-pir.html +187 -0
- package/nodes/velbus-pir/velbus-pir.js +269 -0
- package/nodes/velbus-pir-20/velbus-pir-20.html +186 -0
- package/nodes/velbus-pir-20/velbus-pir-20.js +352 -0
- package/nodes/velbus-relay/velbus-relay.html +215 -0
- package/nodes/velbus-relay/velbus-relay.js +404 -0
- package/nodes/velbus-relay-20/velbus-relay-20.html +123 -0
- package/nodes/velbus-relay-20/velbus-relay-20.js +434 -0
- package/nodes/velbus-scan/velbus-scan.html +87 -0
- package/nodes/velbus-scan/velbus-scan.js +313 -0
- package/nodes/velbus-sensor/velbus-sensor.html +154 -0
- package/nodes/velbus-sensor/velbus-sensor.js +259 -0
- package/nodes/velbus-sensor-20/velbus-sensor-20.html +158 -0
- package/nodes/velbus-sensor-20/velbus-sensor-20.js +314 -0
- package/nodes/velbus-thermostat/velbus-thermostat.html +191 -0
- package/nodes/velbus-thermostat/velbus-thermostat.js +322 -0
- package/package.json +55 -0
- package/velbus-2026-repo.bundle +0 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* dimmer-types-20.js
|
|
5
|
+
* Registry of V2 (-20 series) Velbus dimmer/output module types.
|
|
6
|
+
* Original series modules are in dimmer-types.js.
|
|
7
|
+
*
|
|
8
|
+
* ALL THREE MODULES SHARE IDENTICAL PACKET STRUCTURE.
|
|
9
|
+
* The only behavioural difference is the dim curve:
|
|
10
|
+
* linear — VMB2DC-20, VMB8DC-20 (0-10V DC output)
|
|
11
|
+
* exponential — VMB4LEDPWM-20 (PWM LED output, perceptual curve)
|
|
12
|
+
*
|
|
13
|
+
* WHAT THESE MODULES OUTPUT:
|
|
14
|
+
* VMB2DC-20 / VMB8DC-20: 0-10V DC control voltage per channel.
|
|
15
|
+
* No mains load. Drives dimmer packs (Finder, Mode Lighting etc.),
|
|
16
|
+
* linear actuators, variable valves, any 0-10V compatible input.
|
|
17
|
+
* VMB4LEDPWM-20: Direct PWM per channel for LED strips/drivers.
|
|
18
|
+
*
|
|
19
|
+
* VMB4LEDPWM-20 OUTPUT GROUPING MODES:
|
|
20
|
+
* The four PWM channels can be grouped in three ways. This is a
|
|
21
|
+
* hardware/memory configuration decision made at commissioning time.
|
|
22
|
+
* The mode must match the physical wiring.
|
|
23
|
+
*
|
|
24
|
+
* 'single' — 4 independent single-colour channels (default)
|
|
25
|
+
* CH1, CH2, CH3, CH4 each drive separate LED circuits.
|
|
26
|
+
* Use cmd: 'set' per channel.
|
|
27
|
+
*
|
|
28
|
+
* 'rgb' — CH1=Red, CH2=Green, CH3=Blue form one RGB group.
|
|
29
|
+
* CH4 remains independent.
|
|
30
|
+
* Use cmd: 'rgbw' for the group (W byte ignored).
|
|
31
|
+
* Use cmd: 'set' for CH4.
|
|
32
|
+
*
|
|
33
|
+
* 'rgbw' — All four channels form one RGBW group.
|
|
34
|
+
* CH1=Red, CH2=Green, CH3=Blue, CH4=White.
|
|
35
|
+
* Use cmd: 'rgbw' for all colour control.
|
|
36
|
+
*
|
|
37
|
+
* RESOLVED (protocol PDF ed.2, 01/07/2025): there is no single "mode byte".
|
|
38
|
+
* The mode is the emergent result of each channel's per-channel "Device Type"
|
|
39
|
+
* setting (settings index 25). Channel 1 = 0x08 (RGBW control) means the
|
|
40
|
+
* module is in 'rgbw' mode; channel 1 = 0xF0 (RGB control) means 'rgb' mode;
|
|
41
|
+
* any single-lamp type (typically 0x06, LED module) on every channel means
|
|
42
|
+
* 'single' mode. See DEVICE_TYPE_NAMES below for the full value table.
|
|
43
|
+
*
|
|
44
|
+
* Read via the settings API: 0xE7 [channel, 0x00, 25] request →
|
|
45
|
+
* 0xE8 [channel, 25, device_type] reply. This node's 'get_device_type'
|
|
46
|
+
* input command performs this read and reports the detected mode on
|
|
47
|
+
* output 1, warning on output 2 if it disagrees with the configured
|
|
48
|
+
* ledMode. Direct memory addresses also exist (0x066C/0x06D0/0x0734/0x0798,
|
|
49
|
+
* 0x64-byte stride per channel) but are for VLP-level analysis only —
|
|
50
|
+
* this node always uses the settings API, never a raw memory write.
|
|
51
|
+
*
|
|
52
|
+
* This node exposes the mode as a config property so the correct command
|
|
53
|
+
* set can be applied and documented. It does NOT write the mode to the
|
|
54
|
+
* module — that remains a deliberate commissioning-time decision, made by
|
|
55
|
+
* the installer or the VelbusAI commissioning agent, never automatically.
|
|
56
|
+
*
|
|
57
|
+
* CRITICAL: Sending individual channel dim commands to a module
|
|
58
|
+
* configured as 'rgb' or 'rgbw' bypasses colour coordination.
|
|
59
|
+
* The result will look wrong. Always confirm mode before commissioning.
|
|
60
|
+
*
|
|
61
|
+
* KEY PROTOCOL NOTES:
|
|
62
|
+
* Status packet: 0xEE (NOT 0xFB or 0xB8)
|
|
63
|
+
* Dim value: 0-254 raw (NOT 0-100%)
|
|
64
|
+
* Dim value pkt: 0xA5 (up to 4 channels packed per packet)
|
|
65
|
+
* Set dim: 0x07 + channel + value(0-254) + fade_mode
|
|
66
|
+
* fade_mode: 0=direct, 1=rate, 2=time
|
|
67
|
+
* RGBW: 0x1E + group + R + G + B + W + fade_mode
|
|
68
|
+
* Scenes: 16 scenes (S0-S15), command 0x1D
|
|
69
|
+
* 0xFF response: 8 bytes (properties byte: CAN FD, terminator, HW ver)
|
|
70
|
+
* Channel 0xFF: broadcast to all channels
|
|
71
|
+
*
|
|
72
|
+
* NOTE: VMB2DC-20, VMB8DC-20 and VMB4LEDPWM-20 PDFs contain DALI-referencing
|
|
73
|
+
* commands. These are documentation bleed-over from the shared VMBDALI
|
|
74
|
+
* codebase and are INVALID for all three modules. Ignore all DALI references.
|
|
75
|
+
*
|
|
76
|
+
* Confirmed on Toulouse site (26/06/2026):
|
|
77
|
+
* VMB8DC-20 type 0x4B — present on site, channels 1/4/8 verified live.
|
|
78
|
+
*
|
|
79
|
+
* Fields:
|
|
80
|
+
* name - Human-readable module name
|
|
81
|
+
* channels - Number of output channels
|
|
82
|
+
* outputType - '0-10V' or 'PWM'
|
|
83
|
+
* dimCurve - 'linear' or 'exponential'
|
|
84
|
+
* ledMode - VMB4LEDPWM-20 only: 'single'|'rgb'|'rgbw'|null
|
|
85
|
+
* null = not applicable (VMB2DC-20, VMB8DC-20)
|
|
86
|
+
* minMemoryMapVersion - minimum map version required (null = unverified)
|
|
87
|
+
*/
|
|
88
|
+
const DIMMER_TYPES_20 = {
|
|
89
|
+
0x24: { name: 'VMB2DC-20', channels: 2, outputType: '0-10V', dimCurve: 'linear', ledMode: null, minMemoryMapVersion: null },
|
|
90
|
+
0x4B: { name: 'VMB8DC-20', channels: 8, outputType: '0-10V', dimCurve: 'linear', ledMode: null, minMemoryMapVersion: null },
|
|
91
|
+
0x06: { name: 'VMB4LEDPWM-20', channels: 4, outputType: 'PWM', dimCurve: 'exponential', ledMode: 'single', minMemoryMapVersion: null },
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const DIMMER_TYPE_IDS_20 = new Set(Object.keys(DIMMER_TYPES_20).map(Number));
|
|
95
|
+
|
|
96
|
+
// Type bytes for which ledMode configuration is applicable
|
|
97
|
+
const LEDPWM_TYPE_IDS = new Set([0x06]);
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* VMB4LEDPWM-20 per-channel "Device Type" setting (settings index 25).
|
|
101
|
+
* Read via 0xE7/0xE8 settings API — see doc comment above.
|
|
102
|
+
* Source: VMB4LEDPWM-20 protocol PDF ed.2 (01/07/2025).
|
|
103
|
+
*/
|
|
104
|
+
const DEVICE_TYPE_NAMES = {
|
|
105
|
+
0x00: 'Fluorescent lamps',
|
|
106
|
+
0x01: 'Emergency lamps',
|
|
107
|
+
0x02: 'Discharge lamps',
|
|
108
|
+
0x03: 'Low voltage lamps',
|
|
109
|
+
0x04: 'Dimmer for incandescent lamps',
|
|
110
|
+
0x05: 'Conversion to DC voltage (1-10V)',
|
|
111
|
+
0x06: 'LED module',
|
|
112
|
+
0x07: 'Switching device (relay)',
|
|
113
|
+
0x08: 'RGBW control (consumes all 4 channels)',
|
|
114
|
+
0x09: 'Sequencer',
|
|
115
|
+
0xF0: 'RGB control (consumes channels 1-3, channel 4 independent)',
|
|
116
|
+
0xFE: 'Device present but type unknown',
|
|
117
|
+
0xFF: 'Device not present (factory default)'
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
module.exports = { DIMMER_TYPES_20, DIMMER_TYPE_IDS_20, LEDPWM_TYPE_IDS, DEVICE_TYPE_NAMES };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* dimmer-types.js
|
|
5
|
+
* Registry of ORIGINAL SERIES Velbus dimmer module types.
|
|
6
|
+
* V2 (-20) modules are in dimmer-types-20.js.
|
|
7
|
+
*
|
|
8
|
+
* KEY PROTOCOL NOTES:
|
|
9
|
+
* Status packet: 0xB8 (NOT 0xEE or 0xFB)
|
|
10
|
+
* Dim value: 0-100% (NOT 0-254)
|
|
11
|
+
* Dimspeed: 16-bit seconds
|
|
12
|
+
* 0xFF response: 7 bytes (no properties byte — original series)
|
|
13
|
+
* Channel: 0x01 fixed for VMBDMI/VMBDMI-R, bitmask for VMB4DC
|
|
14
|
+
*
|
|
15
|
+
* STATUS BYTE DIFFERENCES:
|
|
16
|
+
* VMBDMI / VMBDMI-R: mode(2b) + error(2b) + loadType(1b) + tempBand(3b)
|
|
17
|
+
* VMB4DC: mode(2b) only
|
|
18
|
+
*
|
|
19
|
+
* Fields:
|
|
20
|
+
* name - Human-readable module name
|
|
21
|
+
* channels - Number of dimmer channels
|
|
22
|
+
* hasThermal - true if thermal status in 0xB8 byte3 (VMBDMI/R only)
|
|
23
|
+
* channelModel - 'single' (fixed 0x01) or 'bitmask'
|
|
24
|
+
* minMemoryMapVersion - minimum map version required (null = unverified)
|
|
25
|
+
*/
|
|
26
|
+
const DIMMER_TYPES = {
|
|
27
|
+
0x15: { name: 'VMBDMI', channels: 1, hasThermal: true, channelModel: 'single', minMemoryMapVersion: null },
|
|
28
|
+
0x2F: { name: 'VMBDMI-R', channels: 1, hasThermal: true, channelModel: 'single', minMemoryMapVersion: null },
|
|
29
|
+
0x12: { name: 'VMB4DC', channels: 4, hasThermal: false, channelModel: 'bitmask', minMemoryMapVersion: null },
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const DIMMER_TYPE_IDS = new Set(Object.keys(DIMMER_TYPES).map(Number));
|
|
33
|
+
|
|
34
|
+
module.exports = { DIMMER_TYPES, DIMMER_TYPE_IDS };
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
4
|
+
// Glass panel type registry — full VMBEL / VMBGP family
|
|
5
|
+
// Single velbus-glass-panel node handles all entries in this table.
|
|
6
|
+
//
|
|
7
|
+
// hasOled: module has OLED display — DATABYTE8 of 0xED is page number,
|
|
8
|
+
// 0xAC memo text and 0xBE counter status are also emitted
|
|
9
|
+
// hasPir: module has PIR sensor — 0xA9 raw light value emitted
|
|
10
|
+
// hasOc: module has open collector output (channel 18 in protocol)
|
|
11
|
+
// Confirmed from PDF: VMBEL1/2/4 and -20 variants, VMBELO/-20,
|
|
12
|
+
// VMBGPO/-20, VMBELPIR/-20, VMBEL2PIR/-20, VMBGP4PIR/-20.
|
|
13
|
+
// VMBGP1/2/4 original and -2/-20 series: OC NOT confirmed from
|
|
14
|
+
// PDF — VMBGP1-2/2-2/4-2 protocol doc has no OC commands.
|
|
15
|
+
// TO VERIFY ON HARDWARE (UK, post July 4th 2026).
|
|
16
|
+
// hasOc: null = unverified, treat as false until confirmed.
|
|
17
|
+
// pirChannels: channel meanings for PIR variants (1-indexed)
|
|
18
|
+
// keys: channel number, value: semantic label
|
|
19
|
+
// channels: number of physical button channels
|
|
20
|
+
// minMapVer: minimum memory map version required (null = unverified/unknown)
|
|
21
|
+
// series: 'original' | 'v2'
|
|
22
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
const GLASS_PANEL_TYPES = {
|
|
25
|
+
|
|
26
|
+
// ── Original series ───────────────────────────────────────────────────────
|
|
27
|
+
|
|
28
|
+
0x1E: {
|
|
29
|
+
name: 'VMBGP1',
|
|
30
|
+
channels: 1,
|
|
31
|
+
hasOled: false,
|
|
32
|
+
hasPir: false,
|
|
33
|
+
hasOc: null, // TO VERIFY — no PDF read for original VMBGP1
|
|
34
|
+
minMapVer: null,
|
|
35
|
+
series: 'original',
|
|
36
|
+
},
|
|
37
|
+
0x1F: {
|
|
38
|
+
name: 'VMBGP2',
|
|
39
|
+
channels: 2,
|
|
40
|
+
hasOled: false,
|
|
41
|
+
hasPir: false,
|
|
42
|
+
hasOc: null, // TO VERIFY — no PDF read for original VMBGP2
|
|
43
|
+
minMapVer: null,
|
|
44
|
+
series: 'original',
|
|
45
|
+
},
|
|
46
|
+
0x20: {
|
|
47
|
+
name: 'VMBGP4',
|
|
48
|
+
channels: 4,
|
|
49
|
+
hasOled: false,
|
|
50
|
+
hasPir: false,
|
|
51
|
+
hasOc: null, // TO VERIFY — no PDF read, was incorrectly labelled VMB6PB-20
|
|
52
|
+
minMapVer: null,
|
|
53
|
+
series: 'original',
|
|
54
|
+
},
|
|
55
|
+
0x21: {
|
|
56
|
+
name: 'VMBGPO',
|
|
57
|
+
channels: 32,
|
|
58
|
+
hasOled: true,
|
|
59
|
+
hasPir: false,
|
|
60
|
+
hasOc: true, // OLED/output variant — OC confirmed by protocol family
|
|
61
|
+
minMapVer: 2,
|
|
62
|
+
series: 'original',
|
|
63
|
+
},
|
|
64
|
+
0x2D: {
|
|
65
|
+
name: 'VMBGP4PIR',
|
|
66
|
+
channels: 8,
|
|
67
|
+
hasOled: false,
|
|
68
|
+
hasPir: true,
|
|
69
|
+
hasOc: null, // TO VERIFY on hardware
|
|
70
|
+
pirChannels: {
|
|
71
|
+
1: 'button1', 2: 'button2', 3: 'button3', 4: 'button4',
|
|
72
|
+
5: 'virtual', 6: 'dark', 7: 'light', 8: 'motion',
|
|
73
|
+
},
|
|
74
|
+
minMapVer: null,
|
|
75
|
+
series: 'original',
|
|
76
|
+
},
|
|
77
|
+
0x34: {
|
|
78
|
+
name: 'VMBEL1',
|
|
79
|
+
channels: 1,
|
|
80
|
+
hasOled: false,
|
|
81
|
+
hasPir: false,
|
|
82
|
+
hasOc: true, // Confirmed: VMBEL1/2/4 protocol PDF ed2 Nov 2024
|
|
83
|
+
minMapVer: 2,
|
|
84
|
+
series: 'original',
|
|
85
|
+
},
|
|
86
|
+
0x35: {
|
|
87
|
+
name: 'VMBEL2',
|
|
88
|
+
channels: 2,
|
|
89
|
+
hasOled: false,
|
|
90
|
+
hasPir: false,
|
|
91
|
+
hasOc: true, // Confirmed: VMBEL1/2/4 protocol PDF ed2 Nov 2024
|
|
92
|
+
minMapVer: 2,
|
|
93
|
+
series: 'original',
|
|
94
|
+
},
|
|
95
|
+
0x36: {
|
|
96
|
+
name: 'VMBEL4',
|
|
97
|
+
channels: 4,
|
|
98
|
+
hasOled: false,
|
|
99
|
+
hasPir: false,
|
|
100
|
+
hasOc: true, // Confirmed: VMBEL1/2/4 protocol PDF ed2 Nov 2024
|
|
101
|
+
minMapVer: 2,
|
|
102
|
+
series: 'original',
|
|
103
|
+
},
|
|
104
|
+
0x37: {
|
|
105
|
+
name: 'VMBELO',
|
|
106
|
+
channels: 4,
|
|
107
|
+
hasOled: true,
|
|
108
|
+
hasPir: false,
|
|
109
|
+
hasOc: true, // OLED/output variant — OC confirmed by protocol family
|
|
110
|
+
minMapVer: 4,
|
|
111
|
+
series: 'original',
|
|
112
|
+
},
|
|
113
|
+
0x38: {
|
|
114
|
+
name: 'VMBELPIR',
|
|
115
|
+
channels: 8,
|
|
116
|
+
hasOled: false,
|
|
117
|
+
hasPir: true,
|
|
118
|
+
hasOc: true, // PIR variant of VMBEL family — OC present
|
|
119
|
+
pirChannels: {
|
|
120
|
+
1: 'button1', 2: 'button2', 3: 'button3', 4: 'button4',
|
|
121
|
+
5: 'virtual', 6: 'dark', 7: 'light', 8: 'motion',
|
|
122
|
+
},
|
|
123
|
+
minMapVer: 2,
|
|
124
|
+
series: 'original',
|
|
125
|
+
},
|
|
126
|
+
0x3A: {
|
|
127
|
+
name: 'VMBGP1-2',
|
|
128
|
+
channels: 1,
|
|
129
|
+
hasOled: false,
|
|
130
|
+
hasPir: false,
|
|
131
|
+
hasOc: false, // VMBGP1-2/2-2/4-2 PDF has no OC commands — TO VERIFY on hardware
|
|
132
|
+
minMapVer: null,
|
|
133
|
+
series: 'original',
|
|
134
|
+
},
|
|
135
|
+
0x3B: {
|
|
136
|
+
name: 'VMBGP2-2',
|
|
137
|
+
channels: 2,
|
|
138
|
+
hasOled: false,
|
|
139
|
+
hasPir: false,
|
|
140
|
+
hasOc: false, // VMBGP1-2/2-2/4-2 PDF has no OC commands — TO VERIFY on hardware
|
|
141
|
+
minMapVer: null,
|
|
142
|
+
series: 'original',
|
|
143
|
+
},
|
|
144
|
+
0x3C: {
|
|
145
|
+
name: 'VMBGP4-2',
|
|
146
|
+
channels: 4,
|
|
147
|
+
hasOled: false,
|
|
148
|
+
hasPir: false,
|
|
149
|
+
hasOc: false, // VMBGP1-2/2-2/4-2 PDF has no OC commands — TO VERIFY on hardware
|
|
150
|
+
minMapVer: null,
|
|
151
|
+
series: 'original',
|
|
152
|
+
},
|
|
153
|
+
0x3D: {
|
|
154
|
+
name: 'VMBGPOD-2',
|
|
155
|
+
channels: 4,
|
|
156
|
+
hasOled: true,
|
|
157
|
+
hasPir: false,
|
|
158
|
+
hasOc: null, // OLED variant of GP series — TO VERIFY on hardware
|
|
159
|
+
minMapVer: 2,
|
|
160
|
+
series: 'original',
|
|
161
|
+
},
|
|
162
|
+
0x47: {
|
|
163
|
+
name: 'VMBEL2PIR',
|
|
164
|
+
channels: 6,
|
|
165
|
+
hasOled: false,
|
|
166
|
+
hasPir: true,
|
|
167
|
+
hasOc: true, // PIR variant of VMBEL family — OC present
|
|
168
|
+
pirChannels: {
|
|
169
|
+
1: 'button1', 2: 'button2',
|
|
170
|
+
3: 'virtual', 4: 'dark', 5: 'light', 6: 'motion',
|
|
171
|
+
},
|
|
172
|
+
minMapVer: null,
|
|
173
|
+
series: 'original',
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
// ── V2 series ─────────────────────────────────────────────────────────────
|
|
177
|
+
|
|
178
|
+
0x4F: {
|
|
179
|
+
name: 'VMBEL1-20',
|
|
180
|
+
channels: 1,
|
|
181
|
+
hasOled: false,
|
|
182
|
+
hasPir: false,
|
|
183
|
+
hasOc: true, // Confirmed: VMBEL1/2/4 protocol PDF ed2 Nov 2024 covers -20 variants
|
|
184
|
+
minMapVer: null,
|
|
185
|
+
series: 'v2',
|
|
186
|
+
},
|
|
187
|
+
0x50: {
|
|
188
|
+
name: 'VMBEL2-20',
|
|
189
|
+
channels: 2,
|
|
190
|
+
hasOled: false,
|
|
191
|
+
hasPir: false,
|
|
192
|
+
hasOc: true, // Confirmed: VMBEL1/2/4 protocol PDF ed2 Nov 2024 covers -20 variants
|
|
193
|
+
minMapVer: null,
|
|
194
|
+
series: 'v2',
|
|
195
|
+
},
|
|
196
|
+
0x51: {
|
|
197
|
+
name: 'VMBEL4-20',
|
|
198
|
+
channels: 4,
|
|
199
|
+
hasOled: false,
|
|
200
|
+
hasPir: false,
|
|
201
|
+
hasOc: true, // Confirmed: VMBEL1/2/4 protocol PDF ed2 Nov 2024 covers -20 variants
|
|
202
|
+
minMapVer: null,
|
|
203
|
+
series: 'v2',
|
|
204
|
+
},
|
|
205
|
+
0x52: {
|
|
206
|
+
name: 'VMBELO-20',
|
|
207
|
+
channels: 4,
|
|
208
|
+
hasOled: true,
|
|
209
|
+
hasPir: false,
|
|
210
|
+
hasOc: true, // OLED/output variant — OC confirmed by protocol family
|
|
211
|
+
minMapVer: null,
|
|
212
|
+
series: 'v2',
|
|
213
|
+
},
|
|
214
|
+
0x53: {
|
|
215
|
+
name: 'VMBELPIR-20', // Official list shows VMBBEL1PIR-20 — TO VERIFY via VelbusLink
|
|
216
|
+
channels: 8,
|
|
217
|
+
hasOled: false,
|
|
218
|
+
hasPir: true,
|
|
219
|
+
hasOc: true, // PIR variant of VMBEL family — OC present
|
|
220
|
+
pirChannels: {
|
|
221
|
+
1: 'button1', 2: 'button2', 3: 'button3', 4: 'button4',
|
|
222
|
+
5: 'virtual', 6: 'dark', 7: 'light', 8: 'motion',
|
|
223
|
+
},
|
|
224
|
+
minMapVer: null,
|
|
225
|
+
series: 'v2',
|
|
226
|
+
},
|
|
227
|
+
0x54: {
|
|
228
|
+
name: 'VMBGP1-20',
|
|
229
|
+
channels: 1,
|
|
230
|
+
hasOled: false,
|
|
231
|
+
hasPir: false,
|
|
232
|
+
hasOc: null, // TO VERIFY — GP series OC status unconfirmed
|
|
233
|
+
minMapVer: null,
|
|
234
|
+
series: 'v2',
|
|
235
|
+
},
|
|
236
|
+
0x55: {
|
|
237
|
+
name: 'VMBGP2-20',
|
|
238
|
+
channels: 2,
|
|
239
|
+
hasOled: false,
|
|
240
|
+
hasPir: false,
|
|
241
|
+
hasOc: null, // TO VERIFY — GP series OC status unconfirmed
|
|
242
|
+
minMapVer: null,
|
|
243
|
+
series: 'v2',
|
|
244
|
+
},
|
|
245
|
+
0x56: {
|
|
246
|
+
name: 'VMBGP4-20',
|
|
247
|
+
channels: 4,
|
|
248
|
+
hasOled: false,
|
|
249
|
+
hasPir: false,
|
|
250
|
+
hasOc: null, // TO VERIFY — GP series OC status unconfirmed
|
|
251
|
+
minMapVer: null,
|
|
252
|
+
series: 'v2',
|
|
253
|
+
},
|
|
254
|
+
0x57: {
|
|
255
|
+
name: 'VMBGPO-20',
|
|
256
|
+
channels: 32,
|
|
257
|
+
hasOled: true,
|
|
258
|
+
hasPir: false,
|
|
259
|
+
hasOc: true, // OLED/output variant — OC confirmed by protocol family
|
|
260
|
+
minMapVer: null,
|
|
261
|
+
series: 'v2',
|
|
262
|
+
},
|
|
263
|
+
0x5C: {
|
|
264
|
+
name: 'VMBEL2PIR-20', // Official list shows VMBBEL2PIR-20 / VMBEL4PIR-20 conflict — TO VERIFY via VelbusLink
|
|
265
|
+
channels: 6,
|
|
266
|
+
hasOled: false,
|
|
267
|
+
hasPir: true,
|
|
268
|
+
hasOc: true, // PIR variant of VMBEL family — OC present
|
|
269
|
+
pirChannels: {
|
|
270
|
+
1: 'button1', 2: 'button2',
|
|
271
|
+
3: 'virtual', 4: 'dark', 5: 'light', 6: 'motion',
|
|
272
|
+
},
|
|
273
|
+
minMapVer: null,
|
|
274
|
+
series: 'v2',
|
|
275
|
+
},
|
|
276
|
+
0x5F: {
|
|
277
|
+
name: 'VMBGP4PIR-20',
|
|
278
|
+
channels: 8,
|
|
279
|
+
hasOled: false,
|
|
280
|
+
hasPir: true,
|
|
281
|
+
hasOc: null, // TO VERIFY — GP4PIR OC status unconfirmed
|
|
282
|
+
pirChannels: {
|
|
283
|
+
1: 'button1', 2: 'button2', 3: 'button3', 4: 'button4',
|
|
284
|
+
5: 'virtual', 6: 'dark', 7: 'light', 8: 'motion',
|
|
285
|
+
},
|
|
286
|
+
minMapVer: null,
|
|
287
|
+
series: 'v2',
|
|
288
|
+
},
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
// Flat set of all type byte values — used for quick membership test in scan node
|
|
292
|
+
const GLASS_PANEL_TYPE_IDS = new Set(
|
|
293
|
+
Object.keys(GLASS_PANEL_TYPES).map(k => parseInt(k))
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
module.exports = { GLASS_PANEL_TYPES, GLASS_PANEL_TYPE_IDS };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
4
|
+
// PIR module type registry — V2 (-20) series
|
|
5
|
+
// Covered by velbus-pir-20 node.
|
|
6
|
+
//
|
|
7
|
+
// hasTempSensor: module has temperature sensor — 0xE6 emitted, 0xE8 part1
|
|
8
|
+
// is full glass-panel-style multi-part format (only calibration
|
|
9
|
+
// and alarm fields meaningful — no thermostat presets).
|
|
10
|
+
// Temp alarm bits replace absence in 0x00 bitmask.
|
|
11
|
+
// lockStyle: 'number' — DB2 of lock/unlock is channel number 1-N
|
|
12
|
+
// channels: named channel numbers (1-indexed), keyed by channel number
|
|
13
|
+
// minMapVer: minimum memory map version (null = unverified)
|
|
14
|
+
// series: 'v2'
|
|
15
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
const PIR_TYPES_20 = {
|
|
18
|
+
0x4D: {
|
|
19
|
+
name: 'VMBPIR-20',
|
|
20
|
+
hasTempSensor: false,
|
|
21
|
+
lockStyle: 'number',
|
|
22
|
+
// Channels 1-7 by number; bitmask uses bit0=dark...bit6=absence
|
|
23
|
+
channels: {
|
|
24
|
+
1: 'dark', 2: 'light', 3: 'motion1', 4: 'ldMotion1',
|
|
25
|
+
5: 'motion2', 6: 'ldMotion2', 7: 'absence',
|
|
26
|
+
},
|
|
27
|
+
// 0x00 bitmask: bit0-bit6 as above, bit7 unused
|
|
28
|
+
bitmask: ['dark', 'light', 'motion1', 'ldMotion1', 'motion2', 'ldMotion2', 'absence'],
|
|
29
|
+
minMapVer: 1,
|
|
30
|
+
series: 'v2',
|
|
31
|
+
},
|
|
32
|
+
0x59: {
|
|
33
|
+
name: 'VMBPIRO-20',
|
|
34
|
+
hasTempSensor: true,
|
|
35
|
+
lockStyle: 'number',
|
|
36
|
+
// Channels 1-6 lockable; bits 6-7 are temp alarms (read-only, not lockable)
|
|
37
|
+
channels: {
|
|
38
|
+
1: 'dark', 2: 'light', 3: 'motion1', 4: 'ldMotion1',
|
|
39
|
+
5: 'motion2', 6: 'ldMotion2',
|
|
40
|
+
},
|
|
41
|
+
// 0x00 bitmask: bits 0-5 motion channels, bit6=lowTempAlarm, bit7=highTempAlarm
|
|
42
|
+
bitmask: ['dark', 'light', 'motion1', 'ldMotion1', 'motion2', 'ldMotion2',
|
|
43
|
+
'lowTempAlarm', 'highTempAlarm'],
|
|
44
|
+
minMapVer: null,
|
|
45
|
+
series: 'v2',
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const PIR_TYPE_IDS_20 = new Set(Object.keys(PIR_TYPES_20).map(k => parseInt(k)));
|
|
50
|
+
|
|
51
|
+
module.exports = { PIR_TYPES_20, PIR_TYPE_IDS_20 };
|
package/lib/pir-types.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
4
|
+
// PIR module type registry — original and -10 series
|
|
5
|
+
// Covered by velbus-pir node.
|
|
6
|
+
//
|
|
7
|
+
// hasTempSensor: module has temperature sensor — 0xE6 emitted, 0xE8 settings
|
|
8
|
+
// compact format (7 bytes). Alarms replace absence in bitmask.
|
|
9
|
+
// lockStyle: 'bitmask' — DB2 of lock/unlock/enable/disable is channel bitmask
|
|
10
|
+
// channels: named channel bits in bitmask order (bit0=index0)
|
|
11
|
+
// minMapVer: minimum memory map version (null = unverified)
|
|
12
|
+
// series: 'original' | '-10'
|
|
13
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
const CHANNEL_BITS_WITH_ABSENCE = [
|
|
16
|
+
'dark', 'light', 'motion1', 'ldMotion1', 'motion2', 'ldMotion2', 'absence',
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const CHANNEL_BITS_WITH_TEMP = [
|
|
20
|
+
'dark', 'light', 'motion1', 'ldMotion1', 'motion2', 'ldMotion2',
|
|
21
|
+
'lowTempAlarm', 'highTempAlarm',
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
const PIR_TYPES = {
|
|
25
|
+
0x2A: {
|
|
26
|
+
name: 'VMBPIRM',
|
|
27
|
+
hasTempSensor: false,
|
|
28
|
+
lockStyle: 'bitmask',
|
|
29
|
+
channels: CHANNEL_BITS_WITH_ABSENCE,
|
|
30
|
+
minMapVer: null,
|
|
31
|
+
series: 'original',
|
|
32
|
+
},
|
|
33
|
+
0x2B: {
|
|
34
|
+
name: 'VMBPIRC',
|
|
35
|
+
hasTempSensor: false,
|
|
36
|
+
lockStyle: 'bitmask',
|
|
37
|
+
channels: CHANNEL_BITS_WITH_ABSENCE,
|
|
38
|
+
minMapVer: null,
|
|
39
|
+
series: 'original',
|
|
40
|
+
},
|
|
41
|
+
0x2C: {
|
|
42
|
+
name: 'VMBPIRO',
|
|
43
|
+
hasTempSensor: true,
|
|
44
|
+
lockStyle: 'bitmask',
|
|
45
|
+
channels: CHANNEL_BITS_WITH_TEMP,
|
|
46
|
+
minMapVer: null,
|
|
47
|
+
series: 'original',
|
|
48
|
+
},
|
|
49
|
+
0x23: {
|
|
50
|
+
name: 'VMBPIRO-10',
|
|
51
|
+
hasTempSensor: true,
|
|
52
|
+
lockStyle: 'bitmask',
|
|
53
|
+
channels: CHANNEL_BITS_WITH_TEMP,
|
|
54
|
+
minMapVer: null,
|
|
55
|
+
series: '-10',
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const PIR_TYPE_IDS = new Set(Object.keys(PIR_TYPES).map(k => parseInt(k)));
|
|
60
|
+
|
|
61
|
+
module.exports = { PIR_TYPES, PIR_TYPE_IDS };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* relay-types-20.js
|
|
5
|
+
* Registry of V2 (-20 series) Velbus relay module types.
|
|
6
|
+
* Original series modules are in relay-types.js.
|
|
7
|
+
*
|
|
8
|
+
* KEY PROTOCOL DIFFERENCES FROM ORIGINAL SERIES:
|
|
9
|
+
* 0xFF response: 8 bytes (byte 8 = properties: CAN FD, terminator, HW ver)
|
|
10
|
+
* 0xFB status: One packet = full module state (bitmask per byte, not per-channel)
|
|
11
|
+
* byte 2: channel 1-8 on/off status bitmask
|
|
12
|
+
* byte 3: channel 1-8 inhibited bitmask
|
|
13
|
+
* byte 4: channel 1-8 forced_on bitmask
|
|
14
|
+
* byte 5: channel 1-8 forced_off (locked) bitmask
|
|
15
|
+
* byte 6: channel 1-8 program disabled bitmask
|
|
16
|
+
* byte 7: channel 1-8 interval timer running bitmask
|
|
17
|
+
* byte 8: alarm & program selection
|
|
18
|
+
* Commands use channel NUMBER (1-8) or 0xFF for all — NOT bitmask
|
|
19
|
+
* Full scheduling engine: programs, alarms, sunrise/sunset
|
|
20
|
+
* CAN FD support (flag in 0xFF properties byte)
|
|
21
|
+
* Program steps: 122 (original series: 72)
|
|
22
|
+
*
|
|
23
|
+
* Fields:
|
|
24
|
+
* name - Human-readable module name
|
|
25
|
+
* channels - Number of physical relay channels
|
|
26
|
+
* virtual - Number of virtual channels
|
|
27
|
+
* hasInput - true if module has physical input channel (VMB1RYS-20 ch8)
|
|
28
|
+
* minMemoryMapVersion - minimum map version required (null = unverified)
|
|
29
|
+
*
|
|
30
|
+
* Confirmed type bytes (25/06/2026, from PDF edition 3 Jun 2025):
|
|
31
|
+
* VMB1RYS-20: 0x0D (previously TBD — now confirmed)
|
|
32
|
+
* VMB4RYLD-20: 0x26
|
|
33
|
+
* VMB4RYNO-20: 0x27
|
|
34
|
+
*/
|
|
35
|
+
const RELAY_TYPES_20 = {
|
|
36
|
+
0x0D: { name: 'VMB1RYS-20', channels: 1, virtual: 0, hasInput: true, minMemoryMapVersion: null },
|
|
37
|
+
0x26: { name: 'VMB4RYLD-20', channels: 4, virtual: 4, hasInput: false, minMemoryMapVersion: null },
|
|
38
|
+
0x27: { name: 'VMB4RYNO-20', channels: 4, virtual: 4, hasInput: false, minMemoryMapVersion: null },
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const RELAY_TYPE_IDS_20 = new Set(Object.keys(RELAY_TYPES_20).map(Number));
|
|
42
|
+
|
|
43
|
+
module.exports = { RELAY_TYPES_20, RELAY_TYPE_IDS_20 };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* relay-types.js
|
|
5
|
+
* Registry of ORIGINAL SERIES Velbus relay module types only.
|
|
6
|
+
* V2 (-20) modules are in relay-types-20.js.
|
|
7
|
+
*
|
|
8
|
+
* Fields:
|
|
9
|
+
* name - Human-readable module name
|
|
10
|
+
* channels - Number of physical relay channels
|
|
11
|
+
* virtual - Number of virtual channels
|
|
12
|
+
* hexSwitch - true if address set by physical hex switches
|
|
13
|
+
* hasForcedInhibit - true | 'build1105' | false
|
|
14
|
+
* hasInput - true if module has physical input button (VMB1RYS)
|
|
15
|
+
* minMemoryMapVersion - minimum map version required (null = unverified)
|
|
16
|
+
*
|
|
17
|
+
* Confirmed map versions (Toulouse, 25/06/2026):
|
|
18
|
+
* VMB1RYS 0x41: map version 0, build 2436
|
|
19
|
+
* All other original series assumed 0 pending confirmation.
|
|
20
|
+
*
|
|
21
|
+
* NOTE: Build number bytes in 0xFF response are NOT year/week.
|
|
22
|
+
* They are build number high byte and low byte.
|
|
23
|
+
* (byte6_decimal * 100) + byte7_decimal = build number as shown in VelbusLink.
|
|
24
|
+
*/
|
|
25
|
+
const RELAY_TYPES = {
|
|
26
|
+
0x02: { name: 'VMB1RY', channels: 1, virtual: 0, hexSwitch: true, hasForcedInhibit: false, hasInput: false, minMemoryMapVersion: 0 },
|
|
27
|
+
0x08: { name: 'VMB4RY', channels: 4, virtual: 0, hexSwitch: true, hasForcedInhibit: 'build1105', hasInput: false, minMemoryMapVersion: 0 },
|
|
28
|
+
0x10: { name: 'VMB4RYLD', channels: 4, virtual: 1, hexSwitch: false, hasForcedInhibit: 'build1105', hasInput: false, minMemoryMapVersion: 0 },
|
|
29
|
+
0x11: { name: 'VMB4RYNO', channels: 4, virtual: 1, hexSwitch: false, hasForcedInhibit: 'build1105', hasInput: false, minMemoryMapVersion: 0 },
|
|
30
|
+
0x1B: { name: 'VMB1RYNO', channels: 1, virtual: 4, hexSwitch: false, hasForcedInhibit: 'build1105', hasInput: false, minMemoryMapVersion: 0 },
|
|
31
|
+
0x29: { name: 'VMB1RYNOS', channels: 1, virtual: 4, hexSwitch: false, hasForcedInhibit: true, hasInput: false, minMemoryMapVersion: 0 },
|
|
32
|
+
0x41: { name: 'VMB1RYS', channels: 1, virtual: 4, hexSwitch: false, hasForcedInhibit: true, hasInput: true, minMemoryMapVersion: 0 },
|
|
33
|
+
0x48: { name: 'VMB4RYLD-10', channels: 4, virtual: 1, hexSwitch: false, hasForcedInhibit: true, hasInput: false, minMemoryMapVersion: 0 },
|
|
34
|
+
0x49: { name: 'VMB4RYNO-10', channels: 4, virtual: 1, hexSwitch: false, hasForcedInhibit: true, hasInput: false, minMemoryMapVersion: 0 },
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const RELAY_TYPE_IDS = new Set(Object.keys(RELAY_TYPES).map(Number));
|
|
38
|
+
|
|
39
|
+
module.exports = { RELAY_TYPES, RELAY_TYPE_IDS };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
4
|
+
// Sensor/input module type registry — V2 series
|
|
5
|
+
// Covered by velbus-sensor-20 node.
|
|
6
|
+
//
|
|
7
|
+
// VMB8IN-20 (0x4E): 8 digital inputs + 8 energy counters + up to 24 alarm
|
|
8
|
+
// channels via 3 subaddresses (channels 9-16, 17-24, 25-32)
|
|
9
|
+
// lockStyle: 'number' — DB2 of lock/unlock is channel number 1-32
|
|
10
|
+
// nameStyle: 'number' — DB2 of 0xF0/F1/F2 is channel number 1-32
|
|
11
|
+
// hasCounter: true — 0xA4 energy counter on all 8 channels (Wh / litres / ml)
|
|
12
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
const SENSOR_TYPES_20 = {
|
|
15
|
+
0x4E: {
|
|
16
|
+
name: 'VMB8IN-20',
|
|
17
|
+
channels: 8, // primary digital input channels
|
|
18
|
+
alarmCh: 24, // additional alarm channels via subaddresses (9-32)
|
|
19
|
+
hasCounter: true,
|
|
20
|
+
lockStyle: 'number',
|
|
21
|
+
nameStyle: 'number',
|
|
22
|
+
minMapVer: null,
|
|
23
|
+
series: 'v2',
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const SENSOR_TYPE_IDS_20 = new Set(Object.keys(SENSOR_TYPES_20).map(k => parseInt(k)));
|
|
28
|
+
|
|
29
|
+
module.exports = { SENSOR_TYPES_20, SENSOR_TYPE_IDS_20 };
|