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,337 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
(function() {
|
|
3
|
+
|
|
4
|
+
// ── Glass panel type list for info display ───────────────────────────────
|
|
5
|
+
const GLASS_PANEL_TYPES = {
|
|
6
|
+
0x1E: { name: 'VMBGP1', channels: 1, oled: false, pir: false, series: 'original' },
|
|
7
|
+
0x1F: { name: 'VMBGP2', channels: 2, oled: false, pir: false, series: 'original' },
|
|
8
|
+
0x21: { name: 'VMBGPO', channels: 32, oled: true, pir: false, series: 'original' },
|
|
9
|
+
0x2D: { name: 'VMBGP4PIR', channels: 8, oled: false, pir: true, series: 'original' },
|
|
10
|
+
0x34: { name: 'VMBEL1', channels: 1, oled: false, pir: false, series: 'original' },
|
|
11
|
+
0x35: { name: 'VMBEL2', channels: 2, oled: false, pir: false, series: 'original' },
|
|
12
|
+
0x36: { name: 'VMBEL4', channels: 4, oled: false, pir: false, series: 'original' },
|
|
13
|
+
0x37: { name: 'VMBELO', channels: 4, oled: true, pir: false, series: 'original' },
|
|
14
|
+
0x38: { name: 'VMBELPIR', channels: 8, oled: false, pir: true, series: 'original' },
|
|
15
|
+
0x3A: { name: 'VMBGP1-2', channels: 1, oled: false, pir: false, series: 'original' },
|
|
16
|
+
0x3B: { name: 'VMBGP2-2', channels: 2, oled: false, pir: false, series: 'original' },
|
|
17
|
+
0x3C: { name: 'VMBGP4-2', channels: 4, oled: false, pir: false, series: 'original' },
|
|
18
|
+
0x3D: { name: 'VMBGPOD-2', channels: 4, oled: true, pir: false, series: 'original' },
|
|
19
|
+
0x47: { name: 'VMBEL2PIR', channels: 6, oled: false, pir: true, series: 'original' },
|
|
20
|
+
0x4F: { name: 'VMBEL1-20', channels: 1, oled: false, pir: false, series: 'v2' },
|
|
21
|
+
0x50: { name: 'VMBEL2-20', channels: 2, oled: false, pir: false, series: 'v2' },
|
|
22
|
+
0x51: { name: 'VMBEL4-20', channels: 4, oled: false, pir: false, series: 'v2' },
|
|
23
|
+
0x52: { name: 'VMBELO-20', channels: 4, oled: true, pir: false, series: 'v2' },
|
|
24
|
+
0x53: { name: 'VMBELPIR-20', channels: 8, oled: false, pir: true, series: 'v2' },
|
|
25
|
+
0x54: { name: 'VMBGP1-20', channels: 1, oled: false, pir: false, series: 'v2' },
|
|
26
|
+
0x55: { name: 'VMBGP2-20', channels: 2, oled: false, pir: false, series: 'v2' },
|
|
27
|
+
0x56: { name: 'VMBGP4-20', channels: 4, oled: false, pir: false, series: 'v2' },
|
|
28
|
+
0x57: { name: 'VMBGPO-20', channels: 32, oled: true, pir: false, series: 'v2' },
|
|
29
|
+
0x5C: { name: 'VMBEL2PIR-20', channels: 6, oled: false, pir: true, series: 'v2' },
|
|
30
|
+
0x5F: { name: 'VMBGP4PIR-20', channels: 8, oled: false, pir: true, series: 'v2' },
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
function populateAddressDropdown(bridgeId, selectedAddr, selectedTypeId) {
|
|
34
|
+
const $addr = $('#node-input-address');
|
|
35
|
+
if (!bridgeId) return;
|
|
36
|
+
|
|
37
|
+
$.getJSON('velbus/scan-results?bridge=' + bridgeId, function(results) {
|
|
38
|
+
const modules = (results && results.modules) ? results.modules : [];
|
|
39
|
+
|
|
40
|
+
const gpTypeIds = Object.keys(GLASS_PANEL_TYPES).map(k => parseInt(k));
|
|
41
|
+
const gpModules = modules.filter(function(m) {
|
|
42
|
+
return gpTypeIds.includes(parseInt(m.typeId, 16));
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
if (!gpModules.length) {
|
|
46
|
+
// No glass panels on bus — restore plain text input so user can type manually
|
|
47
|
+
if ($addr.is('select')) {
|
|
48
|
+
const input = $('<input>', {
|
|
49
|
+
type: 'text', id: 'node-input-address',
|
|
50
|
+
placeholder: 'hex address e.g. 0D', style: 'width:80px'
|
|
51
|
+
});
|
|
52
|
+
$addr.replaceWith(input);
|
|
53
|
+
}
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Build select dropdown
|
|
58
|
+
const isSelect = $addr.is('select');
|
|
59
|
+
const $sel = isSelect ? $addr : $('<select>', { id: 'node-input-address', style: 'width:100%' });
|
|
60
|
+
$sel.empty();
|
|
61
|
+
$sel.append($('<option>').val('').text('\u2014 select address \u2014'));
|
|
62
|
+
|
|
63
|
+
gpModules.forEach(function(m) {
|
|
64
|
+
const addrDec = m.addressDec;
|
|
65
|
+
const tid = parseInt(m.typeId, 16);
|
|
66
|
+
const label = m.address + ' \u2014 ' + m.module +
|
|
67
|
+
(m.velbusName && m.velbusName !== m.module ? ' "' + m.velbusName + '"' : '') +
|
|
68
|
+
' (build ' + m.build + ', map v' + m.memoryMapVersion + ')';
|
|
69
|
+
const $opt = $('<option>').val(addrDec).text(label).data('typeid', tid);
|
|
70
|
+
if (addrDec === parseInt(selectedAddr)) $opt.attr('selected', true);
|
|
71
|
+
$sel.append($opt);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Manual entry fallback at bottom
|
|
75
|
+
$sel.append($('<option>').val('__manual__').text('\u2014 enter address manually \u2014'));
|
|
76
|
+
|
|
77
|
+
if (!isSelect) $addr.replaceWith($sel);
|
|
78
|
+
|
|
79
|
+
// Selecting manual entry swaps back to text input
|
|
80
|
+
$sel.on('change', function() {
|
|
81
|
+
if ($(this).val() === '__manual__') {
|
|
82
|
+
const input = $('<input>', {
|
|
83
|
+
type: 'text', id: 'node-input-address',
|
|
84
|
+
placeholder: 'hex e.g. 0D', style: 'width:80px'
|
|
85
|
+
});
|
|
86
|
+
$(this).replaceWith(input);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const addrDec = parseInt($(this).val());
|
|
90
|
+
if (addrDec) updateTypeHint(addrDec, null);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Pre-selected address — set hint
|
|
94
|
+
if (selectedAddr) updateTypeHint(parseInt(selectedAddr), selectedTypeId);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function updateTypeHint(addrDec, knownTypeId) {
|
|
99
|
+
const $hint = $('#gp-type-hint');
|
|
100
|
+
const $typeId = $('#node-input-typeId');
|
|
101
|
+
const $chanCol = $('#gp-channel-count');
|
|
102
|
+
|
|
103
|
+
// Find the selected option to get typeId
|
|
104
|
+
const $opt = $('#node-input-address option[value="' + addrDec + '"]');
|
|
105
|
+
const tid = $opt.data('typeid') || knownTypeId || null;
|
|
106
|
+
|
|
107
|
+
if (tid !== null && GLASS_PANEL_TYPES[tid]) {
|
|
108
|
+
const t = GLASS_PANEL_TYPES[tid];
|
|
109
|
+
$typeId.val('0x' + tid.toString(16).padStart(2, '0').toUpperCase());
|
|
110
|
+
|
|
111
|
+
const extras = [];
|
|
112
|
+
if (t.oled) extras.push('OLED');
|
|
113
|
+
if (t.pir) extras.push('PIR');
|
|
114
|
+
|
|
115
|
+
$hint.text(
|
|
116
|
+
t.name + ' — ' + t.channels + ' ch' +
|
|
117
|
+
(extras.length ? ' · ' + extras.join(', ') : '') +
|
|
118
|
+
' · ' + t.series
|
|
119
|
+
).show();
|
|
120
|
+
|
|
121
|
+
// Auto-fill channel count if field is empty or was auto-filled
|
|
122
|
+
const $ch = $('#node-input-channelCount');
|
|
123
|
+
if (!$ch.val() || $ch.data('auto')) {
|
|
124
|
+
$ch.val(t.channels).data('auto', true);
|
|
125
|
+
}
|
|
126
|
+
} else {
|
|
127
|
+
$hint.hide();
|
|
128
|
+
$typeId.val('');
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
RED.nodes.registerType('velbus-glass-panel', {
|
|
133
|
+
category: 'Velbus (inputs)',
|
|
134
|
+
color: '#3A8C8C',
|
|
135
|
+
defaults: {
|
|
136
|
+
name: { value: '' },
|
|
137
|
+
bridge: { value: '', type: 'velbus-bridge', required: true },
|
|
138
|
+
address: { value: '', required: true, validate: function(v) { return /^(0x)?[0-9a-fA-F]{1,2}$/.test(v); } },
|
|
139
|
+
channelCount: { value: 4, required: true, validate: RED.validators.number() },
|
|
140
|
+
moduleName: { value: '' },
|
|
141
|
+
typeId: { value: '' },
|
|
142
|
+
},
|
|
143
|
+
inputs: 1,
|
|
144
|
+
outputs: 3,
|
|
145
|
+
outputLabels: ['buttons', 'status / thermostat', 'name parts'],
|
|
146
|
+
icon: 'font-awesome/fa-th',
|
|
147
|
+
paletteLabel: 'glass panel',
|
|
148
|
+
|
|
149
|
+
label: function() {
|
|
150
|
+
return this.name || this.moduleName || ('GP 0x' +
|
|
151
|
+
(parseInt(this.address) || 0).toString(16).padStart(2, '0').toUpperCase());
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
oneditprepare: function() {
|
|
155
|
+
const self = this;
|
|
156
|
+
const savedAddr = this.address;
|
|
157
|
+
const savedTypeId = this.typeId ? parseInt(this.typeId, 16) : null;
|
|
158
|
+
|
|
159
|
+
// Type ID field is read-only — populated from scan results
|
|
160
|
+
$('#node-input-typeId').prop('readonly', true).css('background', '#f0f0f0');
|
|
161
|
+
|
|
162
|
+
// Bridge change → refresh dropdown
|
|
163
|
+
$('#node-input-bridge').on('change', function() {
|
|
164
|
+
const bridgeId = $(this).val();
|
|
165
|
+
populateAddressDropdown(bridgeId, savedAddr, savedTypeId);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// Address change → update type hint
|
|
169
|
+
$('#node-input-address').on('change', function() {
|
|
170
|
+
const addrDec = parseInt($(this).val());
|
|
171
|
+
if (addrDec) updateTypeHint(addrDec, null);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Manual channel count edit marks field as no longer auto
|
|
175
|
+
$('#node-input-channelCount').on('input', function() {
|
|
176
|
+
$(this).data('auto', false);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Initial load — deferred so TypedInput has time to render its value.
|
|
180
|
+
// .val() returns '' during oneditprepare; the TypedInput fires 'change'
|
|
181
|
+
// once it has set its value. We trigger that manually after a short delay
|
|
182
|
+
// as a reliable fallback.
|
|
183
|
+
setTimeout(function() {
|
|
184
|
+
$('#node-input-bridge').trigger('change');
|
|
185
|
+
}, 100);
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
oneditsave: function() {
|
|
189
|
+
// Store the address as decimal integer
|
|
190
|
+
const raw = $('#node-input-address').val();
|
|
191
|
+
this.address = parseInt(raw) || 0;
|
|
192
|
+
|
|
193
|
+
// Store typeId from hidden field
|
|
194
|
+
const tid = $('#node-input-typeId').val();
|
|
195
|
+
this.typeId = tid || '';
|
|
196
|
+
|
|
197
|
+
// Store module name from hint for status bar use
|
|
198
|
+
if (tid) {
|
|
199
|
+
const tidNum = parseInt(tid, 16);
|
|
200
|
+
const t = GLASS_PANEL_TYPES[tidNum];
|
|
201
|
+
if (t) this.moduleName = t.name;
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
})();
|
|
207
|
+
</script>
|
|
208
|
+
|
|
209
|
+
<script type="text/html" data-template-name="velbus-glass-panel">
|
|
210
|
+
<div class="form-row">
|
|
211
|
+
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
212
|
+
<input type="text" id="node-input-name" placeholder="Optional label">
|
|
213
|
+
</div>
|
|
214
|
+
|
|
215
|
+
<div class="form-row">
|
|
216
|
+
<label for="node-input-bridge"><i class="fa fa-plug"></i> Bridge</label>
|
|
217
|
+
<input type="text" id="node-input-bridge">
|
|
218
|
+
</div>
|
|
219
|
+
|
|
220
|
+
<div class="form-row">
|
|
221
|
+
<label for="node-input-address"><i class="fa fa-map-marker"></i> Address</label>
|
|
222
|
+
<input type="text" id="node-input-address" placeholder="run scan first, or type hex address" style="width:70%">
|
|
223
|
+
</div>
|
|
224
|
+
|
|
225
|
+
<div class="form-row" id="gp-type-hint-row">
|
|
226
|
+
<label></label>
|
|
227
|
+
<span id="gp-type-hint" style="color:#888; font-size:0.9em; display:none;"></span>
|
|
228
|
+
</div>
|
|
229
|
+
|
|
230
|
+
<div class="form-row" style="display:none">
|
|
231
|
+
<input type="text" id="node-input-typeId">
|
|
232
|
+
<input type="text" id="node-input-moduleName">
|
|
233
|
+
</div>
|
|
234
|
+
|
|
235
|
+
<div class="form-row">
|
|
236
|
+
<label for="node-input-channelCount"><i class="fa fa-list-ol"></i> Channels</label>
|
|
237
|
+
<input type="number" id="node-input-channelCount" min="1" max="32" style="width:80px">
|
|
238
|
+
<span style="margin-left:8px; color:#888; font-size:0.9em;">auto-filled from scan</span>
|
|
239
|
+
</div>
|
|
240
|
+
</script>
|
|
241
|
+
|
|
242
|
+
<script type="text/html" data-help-name="velbus-glass-panel">
|
|
243
|
+
<p style="background:#fff3cd; border-left:4px solid #ffc107; padding:8px 12px; margin-bottom:12px; font-size:0.85em;">
|
|
244
|
+
<strong>⚠ Testing status:</strong> This node was generated with Claude.ai and is in
|
|
245
|
+
need of extensive field testing before being deployed into a commercial project.
|
|
246
|
+
It is presented "as is" — any use beyond testing is entirely at your own risk and liability.
|
|
247
|
+
Constructive feedback is welcomed, accompanied by as many examples and debug captures as possible.
|
|
248
|
+
<a href="https://github.com/MDAR/node-red-contrib-velbus-2026/issues" target="_blank">File an issue on GitHub</a>.
|
|
249
|
+
</p>
|
|
250
|
+
<p>
|
|
251
|
+
Handles all Velbus glass panel and button modules — original and V2 series (VMBEL, VMBGP, VMBELO, VMBELPIR, VMBGPO, VMBGP4PIR families).
|
|
252
|
+
All modules include optional thermostat capability.
|
|
253
|
+
For relay and dimmer outputs see <strong>velbus-relay</strong> / <strong>velbus-dimmer</strong> nodes.
|
|
254
|
+
</p>
|
|
255
|
+
|
|
256
|
+
<h3>Outputs</h3>
|
|
257
|
+
|
|
258
|
+
<h4>Output 1 — Buttons</h4>
|
|
259
|
+
<p>Emitted on button press, release, or long-press (0x00):</p>
|
|
260
|
+
<pre>{
|
|
261
|
+
"type": "button",
|
|
262
|
+
"on": true,
|
|
263
|
+
"pressed": [1, 3],
|
|
264
|
+
"released": [2],
|
|
265
|
+
"longPressed": []
|
|
266
|
+
}</pre>
|
|
267
|
+
<p>For PIR variants (VMBELPIR, VMBGP4PIR etc.) channel numbers are augmented with semantic labels where known:</p>
|
|
268
|
+
<pre>pressed: [{ "channel": 6, "label": "dark" }]</pre>
|
|
269
|
+
|
|
270
|
+
<h4>Output 2 — Status and thermostat</h4>
|
|
271
|
+
<p>Module status (0xED):</p>
|
|
272
|
+
<pre>{
|
|
273
|
+
"type": "status",
|
|
274
|
+
"locked": [],
|
|
275
|
+
"thermostatProgram":"manual",
|
|
276
|
+
"alarms": { "alarm1Active": false, "alarm2Active": false, "selected": 0 },
|
|
277
|
+
"sunreel": 0,
|
|
278
|
+
"oledPage": 1 // OLED types only
|
|
279
|
+
}</pre>
|
|
280
|
+
<p>Thermostat status (0xEA):</p>
|
|
281
|
+
<pre>{
|
|
282
|
+
"type": "thermostat",
|
|
283
|
+
"currentTemp": 21.5,
|
|
284
|
+
"targetTemp": 22.0,
|
|
285
|
+
"mode": "comfort", // comfort | day | night | safe
|
|
286
|
+
"heaterMode": true,
|
|
287
|
+
"heating": false,
|
|
288
|
+
"cooling": false,
|
|
289
|
+
"boostMode": false,
|
|
290
|
+
"thermostatOn": true
|
|
291
|
+
}</pre>
|
|
292
|
+
<p>Temperature (0xE6):</p>
|
|
293
|
+
<pre>{ "type": "temperature", "current": 21.5, "min": 15.0, "max": 30.0 }</pre>
|
|
294
|
+
<p>Light sensor — PIR types only (0xA9):</p>
|
|
295
|
+
<pre>{ "type": "light", "raw": 1024 }</pre>
|
|
296
|
+
<p>Memo text — OLED types only (0xAC):</p>
|
|
297
|
+
<pre>{ "type": "memo", "page": 1, "text": "Hello" }</pre>
|
|
298
|
+
<p>Counter — OLED types only (0xBE):</p>
|
|
299
|
+
<pre>{ "type": "counter", "counter": 1, "value": 42 }</pre>
|
|
300
|
+
|
|
301
|
+
<h4>Output 3 — Name parts</h4>
|
|
302
|
+
<pre>{ "type": "name_part", "part": 0, "text": "Living" }</pre>
|
|
303
|
+
<p>Three parts (0, 1, 2) concatenate to form the full module name as stored in VelbusLink.</p>
|
|
304
|
+
|
|
305
|
+
<h3>Input commands</h3>
|
|
306
|
+
<dl>
|
|
307
|
+
<dt><code>{ "cmd": "comfort" }</code> / <code>"day"</code> / <code>"night"</code> / <code>"safe"</code></dt>
|
|
308
|
+
<dd>Switch thermostat mode. Optional <code>sleepTime</code> (minutes, 0 = until next programme step).</dd>
|
|
309
|
+
|
|
310
|
+
<dt><code>{ "cmd": "set_temp", "pointer": 0, "temp": 21.5 }</code></dt>
|
|
311
|
+
<dd>Set target temperature. pointer: 0=comfort, 1=day, 2=night, 3=safe.</dd>
|
|
312
|
+
|
|
313
|
+
<dt><code>{ "cmd": "led_set", "channel": 1 }</code></dt>
|
|
314
|
+
<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>
|
|
315
|
+
|
|
316
|
+
<dt><code>{ "cmd": "output_on" }</code> / <code>"output_off"</code></dt>
|
|
317
|
+
<dd>Open collector output on/off.</dd>
|
|
318
|
+
|
|
319
|
+
<dt><code>{ "cmd": "output_timer", "duration": 60 }</code></dt>
|
|
320
|
+
<dd>Open collector output timed on (seconds).</dd>
|
|
321
|
+
|
|
322
|
+
<dt><code>{ "cmd": "get_status" }</code></dt>
|
|
323
|
+
<dd>Request module status (triggers 0xED response).</dd>
|
|
324
|
+
|
|
325
|
+
<dt><code>{ "cmd": "get_thermostat" }</code></dt>
|
|
326
|
+
<dd>Request thermostat status (triggers 0xEA response).</dd>
|
|
327
|
+
|
|
328
|
+
<dt><code>{ "cmd": "get_name" }</code></dt>
|
|
329
|
+
<dd>Request module name (triggers three 0xF0/F1/F2 responses on output 3).</dd>
|
|
330
|
+
</dl>
|
|
331
|
+
|
|
332
|
+
<h3>Supported modules</h3>
|
|
333
|
+
<p>
|
|
334
|
+
"Original": VMBGP1, VMBGP2, VMBGPO, VMBGP4PIR, VMBEL1/2/4, VMBELO, VMBELPIR, VMBEL2PIR, VMBGP1/2/4-2, VMBGPOD-2.<br>
|
|
335
|
+
"V2": VMBEL1/2/4-20, VMBELO-20, VMBELPIR-20, VMBEL2PIR-20, VMBGP1/2/4-20, VMBGPO-20, VMBGP4PIR-20.
|
|
336
|
+
</p>
|
|
337
|
+
</script>
|