_loadSpecs() now calls loadCurve(model) instead of returning a hardcoded literal. Default model 'gva-elastox-r' keeps the legacy GVA numbers; the editor cascade (supplier → type → model → unit) lets users pick Jäger, Aerostrip, or PIK/PRK once those curve files land in generalFunctions. Editor changes: - diffuser.js serves /diffuser/menu.js + /diffuser/configData.js - diffuser.html loads the shared MenuManager scripts, includes asset-fields-placeholder + logger-fields-placeholder, and runs the shared init/save lifecycle. - Density field re-labelled "Bottom coverage [%]" — semantics were always meant to be % surface-area coverage; "elements per m²" was a prior mis-conversion. Default flipped 2.4 → 15 (typical fine-bubble). - New defaults: model, unit, assetTagNumber. specificClass: - buildDomainConfig now forwards uiConfig.model/unit/assetTagNumber under config.asset.* so _loadSpecs can resolve it. - _loadSpecs walks config.asset.model || config.model || DEFAULT, falls through to GVA on a missing curve file (with a clear error if neither resolves to a usable otr_curve + p_curve). All 8 unit + structure tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
131 lines
5.1 KiB
HTML
131 lines
5.1 KiB
HTML
<!-- Load the dynamic menu & config endpoints (asset cascade + logger fields) -->
|
|
<script src="/diffuser/menu.js"></script>
|
|
<script src="/diffuser/configData.js"></script>
|
|
|
|
<script type="text/javascript">
|
|
RED.nodes.registerType('diffuser', {
|
|
category: 'EVOLV',
|
|
color: '#86bbdd',
|
|
defaults: {
|
|
name: { value: '', required: true },
|
|
number: { value: 1, required: true },
|
|
i_elements: { value: 1, required: true },
|
|
i_diff_density: { value: 15, required: true },
|
|
i_m_water: { value: 0, required: true },
|
|
alfaf: { value: 0.7, required: true },
|
|
i_zone_volume: { value: 0, required: false },
|
|
processOutputFormat: { value: 'process' },
|
|
dbaseOutputFormat: { value: 'influxdb' },
|
|
|
|
// Asset identifier surface. supplier / assetType / category are derived
|
|
// at runtime via assetResolver.resolveAssetMetadata(model); do NOT add
|
|
// them back here. See generalFunctions/src/registry/README.md.
|
|
assetTagNumber: { value: '' },
|
|
model: { value: '' },
|
|
unit: { value: '' },
|
|
|
|
enableLog: { value: false },
|
|
logLevel: { value: 'error' },
|
|
},
|
|
inputs: 1,
|
|
outputs: 3,
|
|
inputLabels: ['control'],
|
|
outputLabels: ['process', 'dbase', 'parent'],
|
|
icon: 'font-awesome/fa-tint',
|
|
label: function() {
|
|
const stem = this.model ? this.model : (this.name || 'diffuser');
|
|
return this.name ? `${this.name}_${this.number}` : stem;
|
|
},
|
|
|
|
oneditprepare: function() {
|
|
// wait for the menu scripts to load, then hand the node off to the
|
|
// shared asset / logger init code from generalFunctions
|
|
let menuRetries = 0;
|
|
const maxMenuRetries = 100; // 5 s at 50 ms intervals
|
|
const waitForMenuData = () => {
|
|
if (window.EVOLV?.nodes?.diffuser?.initEditor) {
|
|
window.EVOLV.nodes.diffuser.initEditor(this);
|
|
} else if (++menuRetries < maxMenuRetries) {
|
|
setTimeout(waitForMenuData, 50);
|
|
} else {
|
|
console.warn('diffuser: menu scripts failed to load within 5 seconds');
|
|
}
|
|
};
|
|
waitForMenuData();
|
|
},
|
|
|
|
oneditsave: function() {
|
|
// Asset cascade saves model + unit + assetTagNumber
|
|
if (window.EVOLV?.nodes?.diffuser?.assetMenu?.saveEditor) {
|
|
window.EVOLV.nodes.diffuser.assetMenu.saveEditor(this);
|
|
}
|
|
// Logger fields
|
|
if (window.EVOLV?.nodes?.diffuser?.loggerMenu?.saveEditor) {
|
|
window.EVOLV.nodes.diffuser.loggerMenu.saveEditor(this);
|
|
}
|
|
},
|
|
});
|
|
</script>
|
|
|
|
<script type="text/html" data-template-name="diffuser">
|
|
<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="Zone name">
|
|
</div>
|
|
<div class="form-row">
|
|
<label for="node-input-number"><i class="fa fa-list-ol"></i> Number</label>
|
|
<input type="number" id="node-input-number" min="1">
|
|
</div>
|
|
<div class="form-row">
|
|
<label for="node-input-i_elements"><i class="fa fa-th"></i> Elements</label>
|
|
<input type="number" id="node-input-i_elements" min="1">
|
|
</div>
|
|
<div class="form-row">
|
|
<label for="node-input-i_diff_density"><i class="fa fa-braille"></i> Bottom coverage [%]</label>
|
|
<input type="number" id="node-input-i_diff_density" step="0.1" min="0" max="100" placeholder="typical 10-25">
|
|
<div style="font-size:11px;color:#666;margin-left:160px;">
|
|
Fraction of tank floor occupied by diffuser membrane (%). Used as the curve-family key.
|
|
</div>
|
|
</div>
|
|
<div class="form-row">
|
|
<label for="node-input-i_m_water"><i class="fa fa-arrows-v"></i> Water Height</label>
|
|
<input type="number" id="node-input-i_m_water" step="0.1" min="0">
|
|
</div>
|
|
<div class="form-row">
|
|
<label for="node-input-alfaf"><i class="fa fa-flask"></i> Alfa Factor</label>
|
|
<input type="number" id="node-input-alfaf" step="0.01" min="0">
|
|
</div>
|
|
<div class="form-row">
|
|
<label for="node-input-i_zone_volume"><i class="fa fa-cube"></i> Zone Volume</label>
|
|
<input type="number" id="node-input-i_zone_volume" step="0.1" min="0" placeholder="m3">
|
|
</div>
|
|
|
|
<h3>Output Formats</h3>
|
|
<div class="form-row">
|
|
<label for="node-input-processOutputFormat"><i class="fa fa-random"></i> Process Output</label>
|
|
<select id="node-input-processOutputFormat" style="width:60%;">
|
|
<option value="process">process</option>
|
|
<option value="json">json</option>
|
|
<option value="csv">csv</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-row">
|
|
<label for="node-input-dbaseOutputFormat"><i class="fa fa-database"></i> Database Output</label>
|
|
<select id="node-input-dbaseOutputFormat" style="width:60%;">
|
|
<option value="influxdb">influxdb</option>
|
|
<option value="json">json</option>
|
|
<option value="csv">csv</option>
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Asset fields injected here by the shared asset menu (supplier → type → model → unit) -->
|
|
<div id="asset-fields-placeholder"></div>
|
|
|
|
<!-- Logger fields injected here by the shared logger menu -->
|
|
<div id="logger-fields-placeholder"></div>
|
|
</script>
|
|
|
|
<script type="text/html" data-help-name="diffuser">
|
|
<p>Diffused aeration device model. Resolves a supplier curve (SSOTR vs flow per element, DWP vs flow) at the configured bottom-coverage %, and emits the resulting oxygen-transfer rate plus a zone OTR for the parent reactor.</p>
|
|
</script>
|