node-red-contrib-victron-vedirect-usb
Version:
Access the Victron equipment with a USB VE.Direct cable
150 lines (130 loc) • 5.62 kB
HTML
<script type="text/javascript">
(function() {
'use strict';
var VictronVEDirect = {
// Prefer the stable /dev/serial/by-id/... path (survives ttyUSB*
// renumbering across reboots/replugs) when the backend was able to
// resolve one; otherwise fall back to the raw device path.
buildOption: function(port) {
var value = port.byId || port.path;
return $('<option/>').val(value).text(value+' ('+port.manufacturer+': '+port.serialNumber+')').data(port);
},
populateSelect: function(selector, ports) {
selector[0].options.length = 0;
selector.append('<optgroup label="Tested">');
ports.forEach(function(port) {
console.log(port.manufacturer);
if (port.manufacturer === 'VictronEnergy BV') {
selector.append(VictronVEDirect.buildOption(port));
}
});
selector.append('</optgroup><optgroup label="Untested">');
ports.forEach(function(port) {
if (port.manufacturer !== 'VictronEnergy BV') {
selector.append(VictronVEDirect.buildOption(port));
}
});
selector.append('</optgroup>');
selector.trigger('change');
},
// Find the <option> whose underlying port data matches the given serial number
findOptionBySerialNumber: function(selector, serialNumber) {
return selector.find('option').filter(function() {
return $(this).data('serialNumber') === serialNumber;
});
},
buildEditPanel: function(node) {
var portSelect = $('#node-input-port');
var serialNumberInput = $('#node-input-serialNumber');
$.getJSON('/victron/vedirect-ports')
.done(function(data) {
if (data.length !== 0) {
VictronVEDirect.populateSelect(portSelect, data);
}
// Prefer matching on the previously stored serial number, since the
// device path (ttyUSB* or by-id) may have changed since this node was
// last saved. Fall back to the stored path if there's no match.
var matched = node.serialNumber
? VictronVEDirect.findOptionBySerialNumber(portSelect, node.serialNumber)
: $();
if (matched.length !== 0) {
portSelect.val(matched.val());
} else if (node.port) {
portSelect.val(node.port);
}
serialNumberInput.val(portSelect.find(':selected').data('serialNumber') || '');
})
.fail(function() {
RED.notify("Unable to access the service endpoint.", "error");
});
portSelect.on('change', function() {
serialNumberInput.val(portSelect.find(':selected').data('serialNumber') || '');
});
}
};
RED.nodes.registerType('victron-vedirect-usb', {
category: 'Victron Energy',
paletteLabel: 'VE.Direct USB',
color: '#f7ab3e',
defaults: {
name: {value: ""},
port: {value: "/dev/ttyUSB0"},
serialNumber: {value: ""},
timeout: {value: 10, validate: function(v) {
return v === "" || v === null || v === undefined || (!isNaN(parseFloat(v)) && parseFloat(v) > 0);
}}
},
inputs: 1,
outputs: 1,
icon: "victronenergy.svg",
label: function() {
return this.name || "VE.Direct USB";
},
oneditprepare: function() {
VictronVEDirect.buildEditPanel(this);
}
});
})();
</script>
<script type="text/html" data-template-name="victron-vedirect-usb">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-row">
<label for="node-input-port"><i class="fa fa-tag"></i> Port</label>
<select id="node-input-port" required>
</select>
</div>
<input type="hidden" id="node-input-serialNumber">
<div class="form-row">
<label for="node-input-timeout"><i class="fa fa-clock-o"></i> Timeout</label>
<input type="number" id="node-input-timeout" placeholder="10" min="0" step="1" style="width: 100px;">
<span> seconds (leave empty to disable stale detection)</span>
</div>
</script>
<script type="text/markdown" data-help-name="victron-vedirect-usb">
A node for VE.Direct USB communication with Victron devices.
### Configuration
Only needed configuration is to select the port where the ttyUSB dongle
is connected to. Make sure that you have rights for reading the dongle
(this might need you to be in group `dialup`).
**Stable device selection**: On Linux, ports are listed by their
`/dev/serial/by-id/...` path when available. Unlike `/dev/ttyUSB0`,
`/dev/ttyUSB1`, etc., this path is tied to the device's USB serial number and
stays the same across reboots and reconnections, even if multiple VE.Direct
cables are plugged in and Linux re-orders the `ttyUSB*` device names. The
underlying serial number is also remembered, so the correct device is still
found even if it was originally configured using a plain `/dev/ttyUSB*` path.
**Timeout**: Configure stale data detection timeout in seconds (default: 10).
If no data is received within this time, the node will stop outputting data
and show a warning status. Leave empty to disable stale detection.
### Input
On each input, the read output gets send out. So use an repeating
inject node to get output every x seconds.
### Status
The status shows a green dot with the connected product when the
node is functioning properly. It will show a yellow dot with "stale data"
when no fresh data has been received within the timeout period. It will
show a red dot with an error message when something is wrong.
</script>