UNPKG

smart-nodes

Version:

Controls light, shutters and more. Includes common used logic and statistic nodes to control your home.

465 lines (435 loc) 20.5 kB
<script type="text/javascript"> (function () { let treeList; let candidateNodesCount = 0; let flows = []; let flowMap = {}; function onEditPrepare(node, targetTypes) { if (!node.links) node.links = []; const activeSubflow = RED.nodes.subflow(node.z); treeList = $("<div>") .css({ width: "100%", height: "100%" }) .appendTo(".node-input-link-row") .treeList({ autoSelect: false }) .on("treelistitemmouseover", function (e, item) { if (item.node) { item.node.highlighted = true; item.node.dirty = true; RED.view.redraw(); } }) .on("treelistitemmouseout", function (e, item) { if (item.node) { item.node.highlighted = false; item.node.dirty = true; RED.view.redraw(); } }); flows = []; flowMap = {}; if (activeSubflow) { flowMap[activeSubflow.id] = { id: activeSubflow.id, class: "red-ui-palette-header", label: "Subflow : " + (activeSubflow.name || activeSubflow.id), expanded: true, children: [] }; flows.push(flowMap[activeSubflow.id]); } else { RED.nodes.eachWorkspace(function (ws) { if (!ws.disabled) { flowMap[ws.id] = { id: ws.id, class: "red-ui-palette-header", label: (ws.label || ws.id) + (node.z === ws.id ? " *" : ""), expanded: true, children: [] }; flows.push(flowMap[ws.id]); } }); } setTimeout(function () { treeList.treeList("show", node.z); }, 100); } function initTreeList(node, targetTypes) { candidateNodesCount = 0; for (const key in flowMap) { flowMap[key].children = []; } let candidateNodes = []; targetTypes.forEach(function (targetType) { candidateNodes = candidateNodes.concat(RED.nodes.filterNodes({ type: targetType })); }); candidateNodes.forEach(function (n) { if (flowMap[n.z]) { const isChecked = (node.links.indexOf(n.id) !== -1) || (n.links || []).indexOf(node.id) !== -1; if (isChecked) { flowMap[n.z].children.push({ id: n.id, node: n, label: n.name || n.id, selected: false, checkbox: false, radio: false }); candidateNodesCount++; } } }); for (const key in flowMap) { flowMap[key].children.sort((a, b) => a.label.localeCompare(b.label)); } const flowsFiltered = flows.filter(function (f) { return f.children.length > 0 }); treeList.treeList("empty"); treeList.treeList("data", flowsFiltered); } function resizeNodeList() { var rows = $("#dialog-form>div:not(.node-input-link-row)"); var height = $("#dialog-form").height(); for (var i = 0; i < rows.length; i++) { height -= $(rows[i]).outerHeight(true); } var editorRow = $("#dialog-form>div.node-input-link-row"); height -= (parseInt(editorRow.css("marginTop")) + parseInt(editorRow.css("marginBottom"))); $(".node-input-link-row").css("height", Math.max(height, 200) + "px"); } RED.nodes.registerType("smart_mixing-valve", { category: "Smart Nodes", paletteLabel: "Mixing Valve", color: "#3FADB5", defaults: { name: { value: "" }, enabled: { value: true }, setpoint: { value: 45 }, time_total: { value: 60 }, time_sampling: { value: 60 }, off_mode: { value: "NOTHING" }, // NOTHING | OPEN | CLOSE valve_mode: { value: "HEATING" }, // HEATING | COOLING outputs: { value: 3 }, output_mode: { value: "OPEN_CLOSE" }, precision: { value: 1.0 }, max_change_percent: { value: 1 }, max_change_temp_difference: { value: 20 }, min_change_time: { value: 100 }, links: { value: [], type: "smart_central-control[]" }, alarm_action: { value: "NOTHING" }, // NOTHING | OPEN | CLOSE critical_temp_max: { value: 100 }, crit_temp_change_percent: { value: 0 }, config_change_date: { value: "" }, }, inputs: 1, outputs: 1, outputLabels: function (index) { return this.output_mode == "OPEN_CLOSE" ? ["Open", "Close", "Status Position"][index] : "Position"; }, icon: "mixing-valve.png", label: function () { return this.name || "Mixing Valve"; }, oneditprepare: function () { let node = this; onEditPrepare(this, ["smart_central-control"]); initTreeList(node, ["smart_central-control"]); $("#node-input-output_mode") .css("max-width", "70%") .typedInput({ type: "num", types: [{ value: "output_mode", options: [ { value: "OPEN_CLOSE", label: node._("mixing-valve.ui.open_close") }, { value: "PERCENTAGE", label: node._("mixing-valve.ui.percentage") }, ] }] }); $("#node-input-output_mode").on("change", function () { if (this.value == "OPEN_CLOSE") { $(".only-open-close").show(); node.outputs = 3; } else { $(".only-open-close").hide(); node.outputs = 1; } }); $("#node-input-setpoint") .css("max-width", "4rem") .spinner({ min: -30, max: 100, change: function (event, ui) { var value = parseInt(this.value); value = isNaN(value) ? 0 : value; value = Math.max(value, parseInt($(this).attr("aria-valuemin"))); value = Math.min(value, parseInt($(this).attr("aria-valuemax"))); if (value !== this.value) $(this).spinner("value", value); }, }); $("#node-input-time_total") .css("max-width", "4rem") .spinner({ min: 0, change: function (event, ui) { var value = parseInt(this.value); value = isNaN(value) ? 0 : value; value = Math.max(value, parseInt($(this).attr("aria-valuemin"))); // value = Math.min(value, parseInt($(this).attr("aria-valuemax"))); if (value !== this.value) $(this).spinner("value", value); }, }); $("#node-input-time_sampling") .css("max-width", "4rem") .spinner({ min: 0, change: function (event, ui) { var value = parseInt(this.value); value = isNaN(value) ? 0 : value; value = Math.max(value, parseInt($(this).attr("aria-valuemin"))); // value = Math.min(value, parseInt($(this).attr("aria-valuemax"))); if (value !== this.value) $(this).spinner("value", value); }, }); $("#node-input-off_mode") .css("max-width", "70%") .typedInput({ types: [{ default: "NOTHING", value: "off_mode", options: [ { value: "NOTHING", label: node._("mixing-valve.ui.nothing") }, { value: "OPEN", label: node._("mixing-valve.ui.open") }, { value: "CLOSE", label: node._("mixing-valve.ui.close") } ], }], }); $("#node-input-valve_mode") .css("max-width", "70%") .typedInput({ types: [{ default: "HEATING", value: "valve_mode", options: [ { value: "HEATING", label: node._("mixing-valve.ui.heating") }, { value: "COOLING", label: node._("mixing-valve.ui.cooling") } ], }], }); $("#node-input-alarm_action") .css("max-width", "70%") .typedInput({ types: [{ value: "alarm_action", default: "NOTHING", options: [ { value: "NOTHING", label: node._("mixing-valve.ui.no_action") }, { value: "OPEN", label: node._("mixing-valve.ui.open") }, { value: "CLOSE", label: node._("mixing-valve.ui.close") } ], }], }); $("#node-input-precision") .css("max-width", "4rem") .spinner({ min: 0.1, max: 1.0, step: 0.1, change: function (event, ui) { var value = parseFloat(this.value); value = isNaN(value) ? 0.0 : value; value = Math.max(value, parseFloat($(this).attr("aria-valuemin"))); value = Math.min(value, parseFloat($(this).attr("aria-valuemax"))); if (value !== this.value) $(this).spinner("value", value); }, }); $("#node-input-max_change_percent") .css("max-width", "4rem") .spinner({ min: 1, max: 100, change: function (event, ui) { var value = parseInt(this.value); value = isNaN(value) ? 0 : value; value = Math.max(value, parseInt($(this).attr("aria-valuemin"))); value = Math.min(value, parseInt($(this).attr("aria-valuemax"))); if (value !== this.value) $(this).spinner("value", value); }, }); $("#node-input-max_change_temp_difference") .css("max-width", "4rem") .spinner({ min: 1, max: 100, change: function (event, ui) { var value = parseInt(this.value); value = isNaN(value) ? 0 : value; value = Math.max(value, parseInt($(this).attr("aria-valuemin"))); value = Math.min(value, parseInt($(this).attr("aria-valuemax"))); if (value !== this.value) $(this).spinner("value", value); }, }); $("#node-input-min_change_time") .css("max-width", "4rem") .spinner({ min: 0, max: 10000, step: 100, change: function (event, ui) { var value = parseInt(this.value); value = isNaN(value) ? 0 : value; value = Math.max(value, parseInt($(this).attr("aria-valuemin"))); value = Math.min(value, parseInt($(this).attr("aria-valuemax"))); if (value !== this.value) $(this).spinner("value", value); }, }); // New fields for critical temperature settings $("#node-input-critical_temp_max") .css("max-width", "4rem") .spinner({ min: 0, max: 100, step: 1, change: function (event, ui) { var value = parseFloat(this.value); value = isNaN(value) ? 0.0 : value; value = Math.max(value, parseFloat($(this).attr("aria-valuemin"))); value = Math.min(value, parseFloat($(this).attr("aria-valuemax"))); if (value !== this.value) $(this).spinner("value", value); }, }); if ($("#node-input-critical_temp_max").val() === "") $("#node-input-critical_temp_max").val("100"); $("#node-input-crit_temp_change_percent") .css("max-width", "4rem") .spinner({ min: 0, max: 100, step: 1, change: function (event, ui) { var value = parseFloat(this.value); value = isNaN(value) ? 0.0 : value; value = Math.max(value, parseFloat($(this).attr("aria-valuemin"))); value = Math.min(value, parseFloat($(this).attr("aria-valuemax"))); if (value !== this.value) $(this).spinner("value", value); }, }); if ($("#node-input-crit_temp_change_percent").val() === "") $("#node-input-crit_temp_change_percent").val("0"); }, onadd: function () { this.links = []; }, oneditsave: function () { let node = this; node.config_change_date = (new Date()).toISOString(); }, oneditresize: resizeNodeList }); })(); </script> <script type="text/html" data-template-name="smart_mixing-valve"> <div class="form-row"> <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="mixing-valve.ui.name"></span></label> <input type="text" id="node-input-name" data-i18n="[placeholder]mixing-valve.ui.name" /> </div> <div class="form-row"> <input type="checkbox" id="node-input-enabled" style="width: 20px;" /> <span for="node-input-enabled" style="width: 200px;"> <span data-i18n="mixing-valve.ui.enabled"></span></span> </div> <div class="form-row"> <label for="node-input-output_mode"><i class="fa fa-hashtag"></i> <span data-i18n="mixing-valve.ui.output_mode"></span></label> <input id="node-input-output_mode" /> </div> <div class="form-row"> <label for="node-input-setpoint"><i class="fa fa-sliders"></i> <span data-i18n="mixing-valve.ui.setpoint"></span></label> <input id="node-input-setpoint" value="0" /> °C </div> <div class="form-row only-open-close"> <label for="node-input-time_total"><i class="fa fa-clock-o"></i> <span data-i18n="mixing-valve.ui.runtime"></span></label> <input id="node-input-time_total" value="0" /> s </div> <div class="form-row"> <label for="node-input-time_sampling"><i class="fa fa-clock-o"></i> <span data-i18n="mixing-valve.ui.sampling"></span></label> <input id="node-input-time_sampling" value="0" /> s </div> <div class="form-row"> <label for="node-input-off_mode"><i class="fa fa-power-off"></i> <span data-i18n="mixing-valve.ui.power_off"></span></label> <input id="node-input-off_mode" /> </div> <div class="form-row"> <label for="node-input-valve_mode"><i class="fa fa-fire"></i> <span data-i18n="mixing-valve.ui.mode"></span></label> <input id="node-input-valve_mode" /> </div> <div class="form-row"> <label for="node-input-alarm_action"><i class="fa fa-exclamation-triangle"></i> <span data-i18n="mixing-valve.ui.alarm_on"></span></label> <input id="node-input-alarm_action"/> </div> <div class="form-row"> <label for="node-input-precision" style="width: 250px;"><i class="fa fa-sliders"></i> <span data-i18n="mixing-valve.ui.precision"></span></label> <input id="node-input-precision" value="1.0" /> °C </div> <div class="form-row"> <label for="node-input-max_change_percent" style="width: 250px;"><i class="fa fa-sliders"></i> <span data-i18n="mixing-valve.ui.max_change_percent"></span></label> <input id="node-input-max_change_percent" value="2" /> % </div> <div class="form-row"> <label for="node-input-max_change_temp_difference" style="width: 250px;"><i class="fa fa-sliders"></i> <span data-i18n="mixing-valve.ui.max_change_temp_difference"></span></label> <input id="node-input-max_change_temp_difference" value="20" /> °C </div> <div class="form-row only-open-close"> <label for="node-input-min_change_time" style="width: 250px;"><i class="fa fa-sliders"></i> <span data-i18n="mixing-valve.ui.min_change_time"></span></label> <input id="node-input-min_change_time" value="0" /> ms </div> <div class="form-row"> <label for="node-input-critical_temp_max" style="width: 250px;"><i class="fa fa-thermometer-half"></i> <span data-i18n="mixing-valve.ui.critical_temp_max"></span></label> <input id="node-input-critical_temp_max" value="100"/> °C </div> <div class="form-row"> <label for="node-input-crit_temp_change_percent" style="width: 250px;"><i class="fa fa-percent"></i> <span data-i18n="mixing-valve.ui.crit_temp_change_percent"></span></label> <input id="node-input-crit_temp_change_percent" value="0"/> % </div> <hr/> <span><i class="fa fa-link"></i> <span data-i18n="mixing-valve.ui.controlled_by_central"></span></span> <div class="form-row node-input-link-row node-input-link-rows"></div> </script>