prisme-flow
Version:
prisme platform flow engine
493 lines (444 loc) • 15.5 kB
HTML
<!--
Created by prisme.io on 09/06/2017.
@author <a href="mailto:hello@prisme.io">savane vamara</a> (prisme.io)
-->
<script type="text/x-red" data-template-name="s7 endpoint">
<div class="form-row">
<ul style="background: #fff; min-width: 600px; margin-bottom: 20px;" id="node-config-s7-endpoint-tabs"></ul>
</div>
<div id="node-config-s7-endpoint-tabs-content" style="min-height: 170px;">
<div id="s7-endpoint-tab-connection" style="display:none">
<div class="form-row">
<label for="node-config-input-address"><i class="fa fa-globe"></i> <span>IP Address</span></label>
<input class="input-append-left" type="text" id="node-config-input-address" style="width: 40%;">
<label for="node-config-input-port" style="margin-left: 10px; width: 35px; "> <span>Port</span></label>
<input type="text" id="node-config-input-port" style="width:45px">
</div>
<div class="form-row">
<label for="node-config-input-rack"><i class="fa fa-globe"></i> <span>Rack</span></label>
<input class="input-append-left" type="text" id="node-config-input-rack" style="width: 40%;">
<label for="node-config-input-slot" style="margin-left: 10px; width: 35px; "> <span>Slot</span></label>
<input type="text" id="node-config-input-slot" style="width:45px">
</div>
<div class="form-row">
<label for="node-config-input-cycletime"><i class="fa fa-refresh"></i> <span>Cycle time</span></label>
<input type="text" id="node-config-input-cycletime" style="width: 60px;"> <span>ms</span>
</div>
<div class="form-row">
<label for="node-config-input-timeout"><i class="fa fa-clock-o"></i> <span data-i18n="s7.endpoint.label.timeout">Timeout</span></label>
<input type="text" id="node-config-input-timeout"style="width: 60px;"> <span>ms</span>
</div>
<div class="form-row">
<label for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="s7.label.name">s7 in</span></label>
<input type="text" id="node-config-input-name">
</div>
</div>
<div id="s7-endpoint-tab-variables" style="display:none">
<div class="form-row" style="margin-bottom:0;">
<label><i class="fa fa-list"></i> <span>Variable list</span></label>
</div>
<div class="form-row node-input-variables-container-row" style="margin-bottom: 0px;">
<div id="node-config-input-variables-container-div" style="box-sizing: border-box; border-radius: 5px; height: 300px; padding: 5px; border: 1px solid #ccc; overflow-y:scroll;">
<ol id="node-config-input-variables-container" style=" list-style-type:none; margin: 0;"></ol>
</div>
</div>
<div class="form-row">
<a href="#" class="editor-button editor-button-small" id="node-config-input-add-variable" style="margin-top: 4px;"><i class="fa fa-plus"></i>
<span>Add</span></a>
</div>
<!--<input type="hidden" id="node-config-input-vartable">-->
</div>
</div>
</script>
<script type="text/x-red" data-help-name="s7 endpoint">
<p>Represents a PLC connection</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('s7 endpoint', {
category: 'config',
defaults: {
address: {
value: "",
validate: RED.validators.regex(/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/)
},
port: {
value: "102",
validate: RED.validators.number()
},
rack: {
value: "0",
validate: RED.validators.number()
},
slot: {
value: "2",
validate: RED.validators.number()
},
cycletime: {
value: 500
},
timeout: {
value: 1500
},
name: {
value: ""
},
vartable: {
value: [{
name: "",
addr: ""
}]
}
},
label: function() {
return this.name || this.address + ":" + this.port + ":" + this.rack + ":" + this.slot;
},
oneditprepare: function() {
var self = this;
var labelName = this._("Name");
var labelAddr = this._("Address");
var labelDel = this._("Remove");
// Prepare tabs
var tabs = RED.tabs.create({
id: "node-config-s7-endpoint-tabs",
onchange: function(tab) {
$("#node-config-s7-endpoint-tabs-content").children().hide();
$("#" + tab.id).show();
}
});
tabs.addTab({
id: "s7-endpoint-tab-connection",
label: this._("Connection")
});
tabs.addTab({
id: "s7-endpoint-tab-variables",
label: this._("Variables")
});
setTimeout(function() {
tabs.resize()
}, 0);
function generateVariable(variable) {
var container = $('<li/>', {
style: "background: #fff; margin:0; padding:8px 0px; border-bottom: 1px solid #ccc;"
});
var row1 = $('<div/>').appendTo(container);
var variableAddr = $('<input/>', {
style: "width: 110px; margin-right: 10px;",
class: "node-config-input-variable-addr",
type: "text",
placeholder: labelAddr
}).appendTo(row1);
var variableName = $('<input/>', {
style: "width: 250px",
class: "node-config-input-variable-name",
type: "text",
placeholder: labelName
}).appendTo(row1);
var finalspan = $('<span/>', {
style: "float: right; margin-right: 10px;"
}).appendTo(row1);
var deleteButton = $('<a/>', {
href: "#",
class: "editor-button editor-button-small",
style: "margin-top: 7px; margin-left: 5px;",
title: labelDel
}).appendTo(finalspan);
$('<i/>', {
class: "fa fa-remove"
}).appendTo(deleteButton);
deleteButton.click(function() {
container.css({
"background": "#fee"
});
container.fadeOut(150, function() {
$(this).remove();
});
});
//populate data
variableAddr.val(variable.addr);
variableName.val(variable.name);
$("#node-config-input-variables-container").append(container);
}
$("#node-config-input-add-variable").click(function() {
generateVariable({
name: "",
addr: ""
});
});
$("#node-config-input-cycletime").spinner({
min: 50
});
$("#node-config-input-timeout").spinner({
min: 500
});
if(self.vartable) {
if(typeof self.vartable == 'string') {
self.vartable = JSON.parse(self.vartable);
}
for (var i = 0; i < self.vartable.length; i++) {
generateVariable(self.vartable[i]);
}
}
},
oneditsave: function() {
var node = this;
var vars = $("#node-config-input-variables-container").children();
node.vartable = [];
vars.each(function(i) {
var elm = $(this);
var v = {
addr: elm.find(".node-config-input-variable-addr").val(),
name: elm.find(".node-config-input-variable-name").val()
}
node.vartable.push(v);
});
//$('#node-config-input-vartable').val(JSON.stringify(node.vartable));
}/*,
oneditresize: function(size) {
var rows = $("#s7-endpoint-tab-variables>div:not(.form-row node-input-variables-container-row)");
var height = size.height;
for (var i = 0; i < rows.size(); i++) {
height -= $(rows[i]).outerHeight(true);
}
var editorRow = $("#s7-endpoint-tab-variables>div.form-row node-input-variables-container-row");
height -= (parseInt(editorRow.css("marginTop")) + parseInt(editorRow.css("marginBottom")));
$("#node-config-input-variables-container-div").css("height", height + "px");
var rules = $("#node-config-input-variables-container").children();
var newWidth = $("#node-config-input-variables-container").width();
rules.each(function(i) {
$(this).find('.node-config-input-variable-name').typedInput("width", newWidth - 180);
});
}*/
});
//# sourceURL=s7EndpointScript.js
</script>
<!-- ######################################################################################## -->
<script type="text/x-red" data-template-name="s7 in">
<div class="form-row">
<label for="node-input-endpoint"><i class="fa fa-bolt"></i> <span>PLC</span></label>
<input type="text" id="node-input-endpoint">
</div>
<div class="form-row">
<label for="node-input-mode"><i class="fa fa-sliders"></i> <span>Mode</span></label>
<select type="text" id="node-input-mode">
<option value="single">Single variable</option>
<option value="all-split">All variables, one per message</option>
<option value="all">All variables</option>
</select>
</div>
<div class="form-row s7-input-var-row">
<label for="node-input-variable"><i class="fa fa-random"></i> <span>Variable</span></label>
<select type="text" id="node-input-variable">
</select>
<span id="s7-custom-var-addr"></span>
</div>
<div class="form-row">
<label> </label>
<input type="checkbox" id="node-input-diff" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-diff" style="width:70%;"><span>Emit only when value changes (diff)</span></label>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span>s7 in</span></label>
<input type="text" id="node-input-name">
</div>
</script>
<script type="text/x-red" data-help-name="s7 in">
<p>Reads data from a S7 PLC</p>
<p>All data is read cyclically from the PLC as configured in the <i>s7 endpoint</i>, but there are three modes of making it available in a flow:</p>
<ul>
<li><b>Single variable:</b> A single variable can be selected from the configured variables, and a message is sent every cycle, or only when it changes if <i>diff</i> is checked. <code>msg.payload</code> contains the variable's value and <code>msg.topic</code> has the variable's name.</li>
<li><b>All variables, one per message:</b> Like the <i>Single variable</i> mode, but for all variables configured. If <i>diff</i> is checked, a message is sent everytime any variable changes. If <i>diff</i> is unchecked, one message is sent for every variable, in every cycle. Care must be taken about the number of messages per second in this mode.</li>
<li><b>All variables:</b> In this mode, <code>msg.payload</code> contains an object with all configured variables and their values. If <i>diff</i> is checked, a message is sent if at least one of the variables changes its value.</li>
</ul>
</script>
<script type="text/javascript">
RED.nodes.registerType('s7 in', {
category: 'plc-input',
defaults: {
endpoint: {
value: "",
type: "s7 endpoint",
required: true
},
mode: {
value: "single"
},
variable: {
value: ""
},
diff: {
value: true
},
name: {
value: ""
}
},
color: "#3FADB5",
inputs: 0,
outputs: 1,
icon: "s7.png",
label: function() {
var self = this;
if (this.name) return this.name;
var endpointNode = RED.nodes.node(this.endpoint);
if (endpointNode) {
return (this.mode == 'single' ? this.variable : null) || endpointNode.label();
}
return this._("s7");
},
labelStyle: function() {
return this.name ? "node_label_italic" : "";
},
oneditprepare: function() {
var self = this;
var varList = $('#node-input-variable');
var varAddr = $('#s7-custom-var-addr');
var modeList = $('#node-input-mode');
var endpointList = $("#node-input-endpoint");
var vars = [];
function updateVarList(endpointId) {
$('#node-input-variable option').remove();
var endpointNode = RED.nodes.node(endpointId);
if (!endpointNode) return;
vars = endpointNode.vartable || [];
if (typeof vars === 'string') vars = JSON.parse(vars);
varList.append($('<option/>', {
disabled: "disabled",
selected: "selected",
style: "display:none;",
text: vars.length ? self._("Select a variable") : self._("No variables")
}));
$.each(vars, function(i, val) {
varList.append($('<option/>', {
value: val.name || val.addr,
text: val.name || val.addr
}));
if(val.name == self.variable) {
varList.val(self.variable);
}
});
}
varList.change(function() {
$.each(vars, function(i, val) {
if(varList.val() == val.name) {
varAddr[0].innerText = val.addr;
return true;
}
});
});
endpointList.change(function() {
updateVarList(endpointList.val());
});
updateVarList(self.endpoint);
modeList.change(function() {
if (modeList.val() == "single") {
varList.parent().show();
} else {
varList.parent().hide();
}
});
modeList.change();
}
});
</script>
<!-- ######################################################################################## -->
<script type="text/x-red" data-template-name="s7 out">
<div class="form-row">
<label for="node-input-endpoint"><i class="fa fa-bolt"></i> <span>PLC</span></label>
<input type="text" id="node-input-endpoint">
</div>
<div class="form-row s7-input-var-row">
<label for="node-input-variable"><i class="fa fa-random"></i> <span>Variable</span></label>
<select type="text" id="node-input-variable">
</select>
<span id="s7-custom-var-addr"></span>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span>s7 out</span></label>
<input type="text" id="node-input-name">
</div>
<div class="form-tips"><span data-i18n="[html]s7.out.disclaimer">Caution when writing data to production PLCs!</span></div>
</script>
<script type="text/x-red" data-help-name="s7 out">
<p>Writes <code>msg.payload</code> to a memory area in a S7 PLC</p>
<p>The variable name can be configured in the node and takes precedence.
If left blank it should be set by <code>msg.variable</code> on the incoming message.</p>
<p><b>Warning:</b> Caution when writing data to production PLCs!</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('s7 out', {
category: 'plc-output',
defaults: {
endpoint: {
value: "",
type: "s7 endpoint",
required: true
},
variable: {
value: ""
},
name: {
value: ""
}
},
color: "#3FADB5",
inputs: 1,
outputs: 0,
icon: "s7.png",
align: 'right',
label: function() {
var self = this;
if (this.name) return this.name;
var endpointNode = RED.nodes.node(this.endpoint);
if (endpointNode) {
return this.variable || endpointNode.label();
}
return this._("s7 out");
},
labelStyle: function() {
return this.name ? "node_label_italic" : "";
},
oneditprepare: function() {
var self = this;
var varList = $('#node-input-variable');
var varAddr = $('#s7-custom-var-addr')[0];
var endpointList = $("#node-input-endpoint");
var vars = [];
function updateVarList(endpointId) {
$('#node-input-variable option').remove();
varList.append($('<option/>', {
//disabled: "disabled",
selected: "selected",
//style: "display:none;",
text: self._("Select a variable"),
value: ""
}));
var endpointNode = RED.nodes.node(endpointId);
if (!endpointNode) return;
vars = endpointNode.vartable || [];
if (typeof vars === 'string') vars = JSON.parse(vars);
$.each(vars, function(i, val) {
varList.append($('<option/>', {
value: val.name || val.addr,
text: val.name || val.addr
}));
if(val.name == self.variable) {
varList.val(self.variable);
}
});
}
varList.change(function() {
varAddr.innerText = ""
$.each(vars, function(i, val) {
if(varList.val() == val.name) {
varAddr.innerText = val.addr;
return true;
}
});
});
endpointList.change(function() {
updateVarList(endpointList.val());
});
updateVarList(self.endpoint);
}
});
</script>