-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
For supporting the i/o extender and writing to digital outputs of the device.
- Loading branch information
1 parent
68b6fbf
commit 03b7f2d
Showing
3 changed files
with
190 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
<script type="text/javascript"> | ||
RED.nodes.registerType('digital-output',{ | ||
category: 'Victron Energy', | ||
color: '#4790d0', | ||
defaults: { | ||
name: {value:""}, | ||
output: {value:"", required:true} | ||
}, | ||
inputs:1, | ||
outputs:0, | ||
icon: "victronenergy.svg", | ||
label: function() { | ||
return this.name || "Digital Output Control"; | ||
}, | ||
paletteLabel: "Digital Output Control", | ||
oneditprepare: function() { | ||
var node = this; | ||
$.getJSON('gpio-outputs/'+this.id, function(data) { | ||
var select = $('#node-input-output'); | ||
var warning = $('#node-warning'); | ||
select.empty(); | ||
if (data.outputs && data.outputs.length > 0) { | ||
$.each(data.outputs, function(i, output) { | ||
select.append($("<option></option>") | ||
.attr("value", output) | ||
.text("Output " + output)); | ||
}); | ||
select.val(node.output); | ||
warning.hide(); | ||
} else { | ||
select.hide(); | ||
warning.show(); | ||
var warningText = "<strong>Warning:</strong> NODE_RED_DBUS_ADDRESS is set"; | ||
if (data.dbusAddress) { | ||
warningText += ` to "${data.dbusAddress}"`; | ||
} | ||
warningText += ". This node will not function, and no digital outputs are available. <br>Make sure NODE_RED_DBUS_ADDRESS is not set for this node to function."; | ||
warning.html(warningText); | ||
} | ||
}).fail(function() { | ||
var select = $('#node-input-output'); | ||
var warning = $('#node-warning'); | ||
select.hide(); | ||
warning.show(); | ||
warning.html("<strong>Warning:</strong> Unable to fetch digital outputs. NODE_RED_DBUS_ADDRESS might be set, preventing this node from functioning. <br>Ensure NODE_RED_DBUS_ADDRESS is not set for this node to function."); | ||
}); | ||
} | ||
}); | ||
</script> | ||
|
||
<script type="text/html" data-template-name="digital-output"> | ||
<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-output"><i class="fa fa-dot-circle-o"></i> Output</label> | ||
<select id="node-input-output"> | ||
<!-- Options will be populated dynamically --> | ||
</select> | ||
</div> | ||
<div class="form-row"> | ||
<div id="node-warning" style="display: none; color: #ff8c00; margin-top: 10px;"></div> | ||
</div> | ||
</script> | ||
|
||
<script type="text/markdown" data-help-name="digital-output"> | ||
# Digital Output Control | ||
|
||
This node writes a 0 or 1 to a selected digital output. | ||
|
||
## Important Note | ||
|
||
This node requires the `NODE_RED_DBUS_ADDRESS` environment variable to NOT be set. If it's set, the node will not function. | ||
|
||
## Input | ||
|
||
The input should be one of the following: | ||
- Boolean: `true` or `false` | ||
- Number: `0` or `1` | ||
- String: `"0"` or `"1"` | ||
|
||
Any truthy value will be written as "1", and any falsy value will be written as "0". | ||
|
||
## Configuration | ||
|
||
- **Name**: Optional name for the node | ||
- **Output**: Select an available digital output from the dropdown list | ||
|
||
## Details | ||
|
||
The node checks for available digital outputs in the `/run/io-ext/gpiochip388/output_[1-9]/value` directory. | ||
|
||
When it receives an input, it writes the corresponding value to the selected digital output file. | ||
|
||
## Status | ||
|
||
- Green dot: Last written output and value (when successful) | ||
- Red ring: Indicates that `NODE_RED_DBUS_ADDRESS` is set (node will not function) | ||
|
||
## Error Handling | ||
|
||
- If `NODE_RED_DBUS_ADDRESS` is set, the node will show a warning with the set value and won't function. | ||
- If an invalid output is selected or there's an error writing to the file, the node will report an error. | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
module.exports = function(RED) { | ||
function DigitalOutputNode(config) { | ||
RED.nodes.createNode(this, config); | ||
var node = this; | ||
|
||
// Check if NODE_RED_DBUS_ADDRESS is set | ||
if (process.env.NODE_RED_DBUS_ADDRESS) { | ||
const errorMsg = `NODE_RED_DBUS_ADDRESS is set to "${process.env.NODE_RED_DBUS_ADDRESS}". This node will not function.`; | ||
node.status({fill:"red", shape:"ring", text:"DBUS Address set"}); | ||
node.error(errorMsg); | ||
return; // Exit the function early | ||
} | ||
|
||
// Initialize node properties | ||
node.gpioPath = '/run/io-ext/gpiochip388'; | ||
node.availableOutputs = []; | ||
|
||
// Function to check available GPIO outputs | ||
function checkAvailableOutputs() { | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
|
||
node.availableOutputs = []; | ||
|
||
for (let i = 1; i <= 9; i++) { | ||
const filePath = path.join(node.gpioPath, `output_${i}`, 'value'); | ||
if (fs.existsSync(filePath)) { | ||
node.availableOutputs.push(i); | ||
} | ||
} | ||
|
||
// Update the dropdown options in the Node-RED editor | ||
node.context().set('availableOutputs', node.availableOutputs); | ||
RED.comms.publish('gpio-outputs', { id: node.id, outputs: node.availableOutputs, dbusAddress: process.env.NODE_RED_DBUS_ADDRESS }); | ||
} | ||
|
||
// Check available outputs on node initialization | ||
checkAvailableOutputs(); | ||
|
||
// Handle incoming messages | ||
node.on('input', function(msg) { | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
|
||
const outputNumber = parseInt(config.output); | ||
const value = (msg.payload === true || msg.payload === 1 || msg.payload === '1') ? '1' : '0'; | ||
|
||
if (node.availableOutputs.includes(outputNumber)) { | ||
const filePath = path.join(node.gpioPath, `output_${outputNumber}`, 'value'); | ||
|
||
fs.writeFile(filePath, value, (err) => { | ||
if (err) { | ||
node.error(`Error writing to GPIO ${outputNumber}: ${err}`); | ||
} else { | ||
node.status({fill:"green", shape:"dot", text:`Output ${outputNumber}: ${value}`}); | ||
} | ||
}); | ||
} else { | ||
node.error(`Invalid output number: ${outputNumber}`); | ||
} | ||
}); | ||
|
||
// Clean up on close | ||
node.on('close', function() { | ||
// Add any cleanup code here if needed | ||
}); | ||
} | ||
|
||
RED.nodes.registerType("digital-output", DigitalOutputNode); | ||
|
||
// Serve the custom node configuration UI | ||
RED.httpAdmin.get("/gpio-outputs/:id", RED.auth.needsPermission("digital-output.read"), function(req, res) { | ||
var node = RED.nodes.getNode(req.params.id); | ||
if (node && node.availableOutputs) { | ||
res.json({outputs: node.availableOutputs, dbusAddress: process.env.NODE_RED_DBUS_ADDRESS}); | ||
} else { | ||
res.status(404).end(); | ||
} | ||
}); | ||
} |