forked from p.vanderwilt/settler
Add register child function and fix whitespace
This commit is contained in:
144
settler.html
144
settler.html
@@ -1,86 +1,86 @@
|
|||||||
<script src="/reactor/menu.js"></script>
|
<script src="/reactor/menu.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
RED.nodes.registerType("settler", {
|
RED.nodes.registerType("settler", {
|
||||||
category: "WWTP",
|
category: "WWTP",
|
||||||
color: "#e4a363",
|
color: "#e4a363",
|
||||||
defaults: {
|
defaults: {
|
||||||
name: { value: "" },
|
name: { value: "" },
|
||||||
TS_set: { value: 0.1, required: true },
|
TS_set: { value: 0.1, required: true },
|
||||||
inlet: { value: 1, required: true }
|
inlet: { value: 1, required: true }
|
||||||
},
|
},
|
||||||
inputs: 1,
|
inputs: 1,
|
||||||
outputs: 3,
|
outputs: 3,
|
||||||
outputLabels: ["process", "dbase", "parent"],
|
outputLabels: ["process", "dbase", "parent"],
|
||||||
icon: "font-awesome/fa-random",
|
icon: "font-awesome/fa-random",
|
||||||
label: function() {
|
label: function() {
|
||||||
return this.name || "Settling basin";
|
return this.name || "Settling basin";
|
||||||
},
|
},
|
||||||
oneditprepare: function() {
|
oneditprepare: function() {
|
||||||
// wait for the menu scripts to load
|
// wait for the menu scripts to load
|
||||||
const waitForMenuData = () => {
|
const waitForMenuData = () => {
|
||||||
if (window.EVOLV?.nodes?.reactor?.initEditor) {
|
if (window.EVOLV?.nodes?.reactor?.initEditor) {
|
||||||
window.EVOLV.nodes.reactor.initEditor(this);
|
window.EVOLV.nodes.reactor.initEditor(this);
|
||||||
} else {
|
} else {
|
||||||
setTimeout(waitForMenuData, 50);
|
setTimeout(waitForMenuData, 50);
|
||||||
}
|
|
||||||
};
|
|
||||||
waitForMenuData();
|
|
||||||
|
|
||||||
$("#node-input-TS_set").typedInput({
|
|
||||||
type:"num",
|
|
||||||
types:["num"]
|
|
||||||
});
|
|
||||||
$("#node-input-inlet").typedInput({
|
|
||||||
type:"num",
|
|
||||||
types:["num"]
|
|
||||||
});
|
|
||||||
},
|
|
||||||
oneditsave: function() {
|
|
||||||
// save logger fields
|
|
||||||
if (window.EVOLV?.nodes?.reactor?.loggerMenu?.saveEditor) {
|
|
||||||
window.EVOLV.nodes.reactor.loggerMenu.saveEditor(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// save position field
|
|
||||||
if (window.EVOLV?.nodes?.measurement?.positionMenu?.saveEditor) {
|
|
||||||
window.EVOLV.nodes.rotatingMachine.positionMenu.saveEditor(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
let TS_set = parseFloat($("#node-input-TS_set").typedInput("value"));
|
|
||||||
if (isNaN(TS_set) || TS_set < 0) {
|
|
||||||
RED.notify("TS is not set correctly", {type: "error"});
|
|
||||||
}
|
|
||||||
let inlet = parseInt($("#node-input-n_inlets").typedInput("value"));
|
|
||||||
if (inlet < 1) {
|
|
||||||
RED.notify("Number of inlets not set correctly", {type: "error"});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
waitForMenuData();
|
||||||
|
|
||||||
|
$("#node-input-TS_set").typedInput({
|
||||||
|
type:"num",
|
||||||
|
types:["num"]
|
||||||
|
});
|
||||||
|
$("#node-input-inlet").typedInput({
|
||||||
|
type:"num",
|
||||||
|
types:["num"]
|
||||||
|
});
|
||||||
|
},
|
||||||
|
oneditsave: function() {
|
||||||
|
// save logger fields
|
||||||
|
if (window.EVOLV?.nodes?.reactor?.loggerMenu?.saveEditor) {
|
||||||
|
window.EVOLV.nodes.reactor.loggerMenu.saveEditor(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// save position field
|
||||||
|
if (window.EVOLV?.nodes?.measurement?.positionMenu?.saveEditor) {
|
||||||
|
window.EVOLV.nodes.rotatingMachine.positionMenu.saveEditor(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
const TS_set = parseFloat($("#node-input-TS_set").typedInput("value"));
|
||||||
|
if (isNaN(TS_set) || TS_set < 0) {
|
||||||
|
RED.notify("TS is not set correctly", {type: "error"});
|
||||||
|
}
|
||||||
|
const inlet = parseInt($("#node-input-n_inlets").typedInput("value"));
|
||||||
|
if (inlet < 1) {
|
||||||
|
RED.notify("Number of inlets not set correctly", {type: "error"});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/html" data-template-name="settler">
|
<script type="text/html" data-template-name="settler">
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||||
<input type="text" id="node-input-name" placeholder="Name">
|
<input type="text" id="node-input-name" placeholder="Name">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-TS_set"><i class="fa fa-tag"></i> Total Solids set point [g m-3]</label>
|
<label for="node-input-TS_set"><i class="fa fa-tag"></i> Total Solids set point [g m-3]</label>
|
||||||
<input type="text" id="node-input-TS_set" placeholder="">
|
<input type="text" id="node-input-TS_set" placeholder="">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-inlet"><i class="fa fa-tag"></i> Assigned inlet return line</label>
|
<label for="node-input-inlet"><i class="fa fa-tag"></i> Assigned inlet return line</label>
|
||||||
<input type="text" id="node-input-inlet" placeholder="#">
|
<input type="text" id="node-input-inlet" placeholder="#">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Logger fields injected here -->
|
<!-- Logger fields injected here -->
|
||||||
<div id="logger-fields-placeholder"></div>
|
<div id="logger-fields-placeholder"></div>
|
||||||
|
|
||||||
<!-- Position fields will be injected here -->
|
<!-- Position fields will be injected here -->
|
||||||
<div id="position-fields-placeholder"></div>
|
<div id="position-fields-placeholder"></div>
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/html" data-help-name="settler">
|
<script type="text/html" data-help-name="settler">
|
||||||
<p>Settling tank</p>
|
<p>Settling tank</p>
|
||||||
</script>
|
</script>
|
||||||
34
settler.js
34
settler.js
@@ -4,23 +4,23 @@ const { MenuManager } = require('generalFunctions');
|
|||||||
|
|
||||||
|
|
||||||
module.exports = function (RED) {
|
module.exports = function (RED) {
|
||||||
// Register the node type
|
// Register the node type
|
||||||
RED.nodes.registerType(nameOfNode, function (config) {
|
RED.nodes.registerType(nameOfNode, function (config) {
|
||||||
// Initialize the Node-RED node first
|
// Initialize the Node-RED node first
|
||||||
RED.nodes.createNode(this, config);
|
RED.nodes.createNode(this, config);
|
||||||
// Then create your custom class and attach it
|
// Then create your custom class and attach it
|
||||||
this.nodeClass = new nodeClass(config, RED, this, nameOfNode);
|
this.nodeClass = new nodeClass(config, RED, this, nameOfNode);
|
||||||
});
|
});
|
||||||
|
|
||||||
const menuMgr = new MenuManager();
|
const menuMgr = new MenuManager();
|
||||||
|
|
||||||
// Serve /settler/menu.js
|
// Serve /settler/menu.js
|
||||||
RED.httpAdmin.get(`/${nameOfNode}/menu.js`, (req, res) => {
|
RED.httpAdmin.get(`/${nameOfNode}/menu.js`, (req, res) => {
|
||||||
try {
|
try {
|
||||||
const script = menuMgr.createEndpoint(nameOfNode, ['logger', 'position']);
|
const script = menuMgr.createEndpoint(nameOfNode, ['logger', 'position']);
|
||||||
res.type('application/javascript').send(script);
|
res.type('application/javascript').send(script);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
res.status(500).send(`// Error generating menu: ${err.message}`);
|
res.status(500).send(`// Error generating menu: ${err.message}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
186
src/nodeClass.js
186
src/nodeClass.js
@@ -2,113 +2,113 @@ const { Settler } = require('./specificClass.js');
|
|||||||
|
|
||||||
|
|
||||||
class nodeClass {
|
class nodeClass {
|
||||||
/**
|
/**
|
||||||
* Node-RED node class for settler.
|
* Node-RED node class for settler.
|
||||||
* @param {object} uiConfig - Node-RED node configuration
|
* @param {object} uiConfig - Node-RED node configuration
|
||||||
* @param {object} RED - Node-RED runtime API
|
* @param {object} RED - Node-RED runtime API
|
||||||
* @param {object} nodeInstance - Node-RED node instance
|
* @param {object} nodeInstance - Node-RED node instance
|
||||||
* @param {string} nameOfNode - Name of the node
|
* @param {string} nameOfNode - Name of the node
|
||||||
*/
|
*/
|
||||||
constructor(uiConfig, RED, nodeInstance, nameOfNode) {
|
constructor(uiConfig, RED, nodeInstance, nameOfNode) {
|
||||||
// Preserve RED reference for HTTP endpoints if needed
|
// Preserve RED reference for HTTP endpoints if needed
|
||||||
this.node = nodeInstance;
|
this.node = nodeInstance;
|
||||||
this.RED = RED;
|
this.RED = RED;
|
||||||
this.name = nameOfNode;
|
this.name = nameOfNode;
|
||||||
this.source = null;
|
this.source = null;
|
||||||
|
|
||||||
this._loadConfig(uiConfig)
|
this._loadConfig(uiConfig)
|
||||||
this._setupClass();
|
this._setupClass();
|
||||||
|
|
||||||
this._attachInputHandler();
|
this._attachInputHandler();
|
||||||
this._registerChild();
|
this._registerChild();
|
||||||
this._startTickLoop();
|
this._startTickLoop();
|
||||||
this._attachCloseHandler();
|
this._attachCloseHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle node-red input messages
|
* Handle node-red input messages
|
||||||
*/
|
*/
|
||||||
_attachInputHandler() {
|
_attachInputHandler() {
|
||||||
this.node.on('input', (msg, send, done) => {
|
this.node.on('input', (msg, send, done) => {
|
||||||
|
|
||||||
switch (msg.topic) {
|
switch (msg.topic) {
|
||||||
case 'registerChild':
|
case 'registerChild':
|
||||||
// Register this node as a parent of the child node
|
// Register this node as a parent of the child node
|
||||||
const childId = msg.payload;
|
const childId = msg.payload;
|
||||||
const childObj = this.RED.nodes.getNode(childId);
|
const childObj = this.RED.nodes.getNode(childId);
|
||||||
this.source.childRegistrationUtils.registerChild(childObj.source, msg.positionVsParent);
|
this.source.childRegistrationUtils.registerChild(childObj.source, msg.positionVsParent);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.log("Unknown topic: " + msg.topic);
|
console.log("Unknown topic: " + msg.topic);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (done) {
|
if (done) {
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse node configuration
|
* Parse node configuration
|
||||||
* @param {object} uiConfig Config set in UI in node-red
|
* @param {object} uiConfig Config set in UI in node-red
|
||||||
*/
|
*/
|
||||||
_loadConfig(uiConfig) {
|
_loadConfig(uiConfig) {
|
||||||
this.config = {
|
this.config = {
|
||||||
general: {
|
general: {
|
||||||
name: uiConfig.name || this.name,
|
name: uiConfig.name || this.name,
|
||||||
id: this.node.id,
|
id: this.node.id,
|
||||||
unit: null,
|
unit: null,
|
||||||
logging: {
|
logging: {
|
||||||
enabled: uiConfig.enableLog,
|
enabled: uiConfig.enableLog,
|
||||||
logLevel: uiConfig.logLevel
|
logLevel: uiConfig.logLevel
|
||||||
}
|
|
||||||
},
|
|
||||||
functionality: {
|
|
||||||
positionVsParent: uiConfig.positionVsParent || 'atEquipment', // Default to 'atEquipment' if not specified
|
|
||||||
softwareType: "settler" // should be set in config manager
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
functionality: {
|
||||||
|
positionVsParent: uiConfig.positionVsParent || 'atEquipment', // Default to 'atEquipment' if not specified
|
||||||
|
softwareType: "settler" // should be set in config manager
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register this node as a child upstream and downstream.
|
* Register this node as a child upstream and downstream.
|
||||||
* Delayed to avoid Node-RED startup race conditions.
|
* Delayed to avoid Node-RED startup race conditions.
|
||||||
*/
|
*/
|
||||||
_registerChild() {
|
_registerChild() {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.node.send([
|
this.node.send([
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
{ topic: 'registerChild', payload: this.node.id, positionVsParent: this.config?.functionality?.positionVsParent || 'atEquipment' }
|
{ topic: 'registerChild', payload: this.node.id, positionVsParent: this.config?.functionality?.positionVsParent || 'atEquipment' }
|
||||||
]);
|
]);
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup settler class
|
* Setup settler class
|
||||||
*/
|
*/
|
||||||
_setupClass() {
|
_setupClass() {
|
||||||
|
|
||||||
this.source = new Settler(this.config); // protect from reassignment
|
this.source = new Settler(this.config); // protect from reassignment
|
||||||
this.node.source = this.source;
|
this.node.source = this.source;
|
||||||
}
|
}
|
||||||
|
|
||||||
_startTickLoop() {
|
_startTickLoop() {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this._tickInterval = setInterval(() => this._tick(), 1000);
|
this._tickInterval = setInterval(() => this._tick(), 1000);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
_tick(){
|
_tick(){
|
||||||
this.node.send([null, null, null]);
|
this.node.send([null, null, null]);
|
||||||
}
|
}
|
||||||
|
|
||||||
_attachCloseHandler() {
|
_attachCloseHandler() {
|
||||||
this.node.on('close', (done) => {
|
this.node.on('close', (done) => {
|
||||||
clearInterval(this._tickInterval);
|
clearInterval(this._tickInterval);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = nodeClass;
|
module.exports = nodeClass;
|
||||||
@@ -10,6 +10,14 @@ class Settler {
|
|||||||
this.measurements = new MeasurementContainer();
|
this.measurements = new MeasurementContainer();
|
||||||
this.childRegistrationUtils = new childRegistrationUtils(this); // Child registration utility
|
this.childRegistrationUtils = new childRegistrationUtils(this); // Child registration utility
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registerChild(child, softwareType) {
|
||||||
|
switch (softwareType) {
|
||||||
|
|
||||||
|
default:
|
||||||
|
this.logger.error(`Unrecognized softwareType: ${softwareType}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { Settler };
|
module.exports = { Settler };
|
||||||
Reference in New Issue
Block a user