node-red-contrib-dde
Version:
A Node-RED talk to DDE endpoints over the network
371 lines (344 loc) • 12.6 kB
HTML
<!--
Copyright: (c) 2019-2020, Guilherme Francescon Cittolin <gfcittolin@gmail.com>
GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
-->
<script type="text/x-red" data-template-name="dde endpoint">
<div class="form-row">
<label for="node-config-input-address"><i class="fa fa-globe"></i> <span data-i18n="dde.label.address"></span></label>
<input class="input-append-left" type="text" id="node-config-input-address" data-i18n="[placeholder]dde.placeholder.address" style="width: 40%;">
<label for="node-config-input-port" style="margin-left: 10px; width: 35px; "> <span data-i18n="dde.label.port"></span></label>
<input type="text" id="node-config-input-port" data-i18n="[placeholder]dde.label.port" style="width: 50px">
</div>
<div class="form-row">
<label for="node-config-input-service"><i class="fa fa-exchange"></i> <span data-i18n="dde.label.service"></span></label>
<input type="text" id="node-config-input-service" data-i18n="[placeholder]dde.placeholder.service">
</div>
<div class="form-row">
<label for="node-config-input-timeout"><i class="fa fa-clock-o"></i> <span data-i18n="dde.label.timeout"></span></label>
<input type="text" id="node-config-input-timeout" data-i18n="[placeholder]dde.label.timeout" style="width: 60px;"> <span>ms</span>
</div>
<div class="form-row">
<label> </label>
<input type="checkbox" id="node-input-trackadvise" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-trackadvise" style="width:70%;"><span data-i18n="dde.label.trackadvise"></span></label>
</div>
<div class="form-row">
<label for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="dde.label.name"></span></label>
<input type="text" id="node-config-input-name" data-i18n="[placeholder]dde.label.name">
</div>
</script>
<script type="text/x-red" data-help-name="dde endpoint">
<p>Configures the connection to a DDE Endpoint</p>
<p>This node was created by <a href="https://netsmarttech.com" target="_blank">Smart-Tech</a> as part of the <a href="https://netsmarttech.com/page/st-one" target="_blank">ST-One</a> project</p>
<p>
Set the address to the IP address of the computer
to connect to, and the service to the remote
service name (e.g. "Excel" or "PROGMAN") we want
to establish a communication
</p>
<p>
The "timeout" field sets the amount of time in ms
we can wait until we consider the connection lost
</p>
<p>
When the "Resubscribe" checkbox is checked, the node
will keep track of all items that were subscribed with
the "Advise" function, resubscribing to them again
in the case the connection is lost
</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('dde endpoint', {
category: 'config',
defaults: {
address: {
value: "",
required: true
},
port: {
value: "8888",
validate: RED.validators.number()
},
service: {
value: "",
required: true
},
timeout: {
value: 10000
},
trackadvise: {
value: true
},
name: {
value: ""
}
},
label: function () {
if (this.name) {
return this.name
} else if (this.service && this.address) {
return this.service + "@" + this.address;
} else {
return "dde endpoint";
}
}
});
</script>
<!-- ######################################################################################## -->
<script type="text/x-red" data-template-name="dde">
<div class="form-row">
<label for="node-input-endpoint"><i class="fa fa-bolt"></i> <span data-i18n="dde.label.endpoint"></span></label>
<input type="text" id="node-input-endpoint" data-i18n="[placeholder]dde.label.endpoint">
</div>
<div class="form-row">
<label for="node-input-function"><i class="fa fa-sliders"></i> <span data-i18n="dde.label.function"></span></label>
<select type="text" id="node-input-function">
<option value="request" data-i18n="dde.function.request"></option>
<option value="poke" data-i18n="dde.function.poke"></option>
<option value="execute" data-i18n="dde.function.execute"></option>
<option value="advise" data-i18n="dde.function.advise"></option>
<option value="advise-stop" data-i18n="dde.function.advise-stop"></option>
<option value="advise-stop-all" data-i18n="dde.function.advise-stop-all"></option>
</select>
</div>
<div class="form-row" id="row-node-input-topic">
<label for="node-input-topic"><i class="fa fa-tasks"></i> <span data-i18n="dde.label.topic"></span></label>
<input type="text" id="node-input-topic" data-i18n="[placeholder]dde.label.topic">
</div>
<div class="form-row" id="row-node-input-item">
<label for="node-input-item"><i class="fa fa-list"></i> <span data-i18n="dde.label.item"></span></label>
<input type="text" id="node-input-item" data-i18n="[placeholder]dde.label.item">
</div>
<div class="form-row" id="row-node-input-command">
<label for="node-input-command"><i class="fa fa-file"></i> <span data-i18n="dde.label.command"></span></label>
<input type="text" id="node-input-command" data-i18n="[placeholder]dde.label.command">
</div>
<div class="form-row" id="row-node-input-format">
<label for="node-input-format"><i class="fa fa-sign-out"></i> <span data-i18n="dde.label.format"></span></label>
<select type="text" id="node-input-format">
<option value=""></option>
<option value="CF_TEXT">CF_TEXT</option>
<option value="CF_BITMAP">CF_BITMAP</option>
<option value="CF_METAFILEPICT">CF_METAFILEPICT</option>
<option value="CF_SYLK">CF_SYLK</option>
<option value="CF_DIF">CF_DIF</option>
<option value="CF_TIFF">CF_TIFF</option>
<option value="CF_OEMTEXT">CF_OEMTEXT</option>
<option value="CF_DIB">CF_DIB</option>
<option value="CF_PALETTE">CF_PALETTE</option>
<option value="CF_PENDATA">CF_PENDATA</option>
<option value="CF_RIFF">CF_RIFF</option>
<option value="CF_WAVE">CF_WAVE</option>
<option value="CF_UNICODETEXT">CF_UNICODETEXT</option>
<option value="CF_ENHMETAFILE">CF_ENHMETAFILE</option>
<option value="CF_HDROP">CF_HDROP</option>
<option value="CF_LOCALE">CF_LOCALE</option>
<option value="CF_DIBV5">CF_DIBV5</option>
<option value="CF_OWNERDISPLAY">CF_OWNERDISPLAY</option>
<option value="CF_DSPTEXT">CF_DSPTEXT</option>
<option value="CF_DSPBITMAP">CF_DSPBITMAP</option>
<option value="CF_DSPMETAFILEPICT">CF_DSPMETAFILEPICT</option>
<option value="CF_DSPENHMETAFILE">CF_DSPENHMETAFILE</option>
<option value="CF_PRIVATEFIRST">CF_PRIVATEFIRST</option>
<option value="CF_PRIVATELAST">CF_PRIVATELAST</option>
<option value="CF_GDIOBJFIRST">CF_GDIOBJFIRST</option>
<option value="CF_GDIOBJLAST">CF_GDIOBJLAST</option>
</select>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="dde.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]dde.label.name">
</div>
</script>
<script type="text/x-red" data-help-name="dde">
<p>Exchange data with a DDE endpoint over the network</p>
<p>This node was created by <a href="https://netsmarttech.com" target="_blank">Smart-Tech</a> as part of the <a href="https://netsmarttech.com/page/st-one" target="_blank">ST-One</a> project</p>
<h3>Inputs</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">any</span></dt>
<dd>The value to be written to an item on the "Poke" function</dd>
<dt>topic <span class="property-type">string</span></dt>
<dd>The DDE topic, when not set on the configuration</dd>
<dt>item <span class="property-type">string</span></dt>
<dd>The DDE item, when not set on the configuration</dd>
<dt>format <span class="property-type">string</span></dt>
<dd>
The data format as specified by DDE, when not set
on the configuration. Defaults to "CF_TEXT"
</dd>
<dt>command <span class="property-type">string</span></dt>
<dd>
The command to be executed with the "Execute" function,
when not preset on the node's configuration
</dd>
</dl>
<h3>Outputs</h3>
<ol>
<li>
Standard Output
<dl class="message-properties">
<dt>payload <span class="property-type">any</span></dt>
<dd>
The value read from the DDE endpoint on the "Request"
function. The value's type is casted to javascript types
on a best-effort manner, falling back to a plain Buffer.
</dd>
</dl>
</li>
<li>
Advise events
<dl class="message-properties">
<dt>payload <span class="property-type">any</span></dt>
<dd>
The new value reported by the event. The same type casting
conditions of the "Request" function applies.
</dd>
<dt>topic <span class="property-type">string</span></dt>
<dd>The DDE topic on which the event occurred</dd>
<dt>item <span class="property-type">string</span></dt>
<dd>The DDE item on which the event occurred</dd>
<dt>format <span class="property-type">string</span></dt>
<dd>The data format of the payload, as specified by DDE</dd>
</dl>
</li>
</ol>
<h3>Details</h3>
<p>
Depending on the "Function" selected, this node can perform different
tasks on the DDE endpoint. Each function has different options that can
be preset on the configuration, or if left blank, the respective message
properties are used
</p>
<p>
Note that the <code>format</code> requested, when required, must be
supported by the server, and the server may return an error for an
unsupported format, or even don't send any response at all. The value
of "CF_TEXT" is a sensible default that most services/topics/items should
support
</p>
<dl class="message-properties">
<dt>Request</dt>
<dd>
Reads the value of an <code>item</code> of a <code>topic</code>, in
the <code>format</code> specified
</dd>
<dt>Poke</dt>
<dd>
Writes the <code>payload</code> value into an <code>item</code> of a
<code>topic</code>, in the <code>format</code> specified
</dd>
<dt>Execute</dt>
<dd>
Executes the <code>command</code> on a <code>topic</code>
</dd>
<dt>Advise</dt>
<dd>
Starts listening for changes of the value of an <code>item</code> of
a <code>topic</code>, in the <code>format</code> specified. Every change
reported by the server gets emitted on the second output
</dd>
<dt>Stop Advise</dt>
<dd>
Stops listening for changes of the value of an <code>item</code> of
a <code>topic</code>, in the <code>format</code> specified
</dd>
<dt>Stop All Advise</dt>
<dd>
Stops listening to all advised items
</dd>
</dl>
</script>
<script type="text/javascript">
RED.nodes.registerType('dde', {
category: 'network',
defaults: {
endpoint: {
value: "",
type: "dde endpoint",
required: true
},
function: {
value: "request",
required: true
},
topic: {
value: ""
},
item: {
value: ""
},
format: {
value: "CF_TEXT"
},
command: {
value: ""
},
name: {
value: ""
},
outputs: {
value: 1
}
},
color: "#5FACE0",
inputs: 1,
outputs: 1,
icon: "win.png",
label: function () {
var self = this;
if (this.name) return this.name;
var endpointNode = RED.nodes.node(this.endpoint);
if (endpointNode) {
if (this.function) {
return endpointNode.label() + ": " + this._("dde.function." + this.function);
} else {
return endpointNode.label()
}
}
return "dde";
},
labelStyle: function () {
return this.name ? "node_label_italic" : "";
},
oneditprepare: function () {
var self = this;
var fieldFunction = $('#node-input-function');
var rowTopic = $('#row-node-input-topic');
var rowItem = $('#row-node-input-item');
var rowFormat = $('#row-node-input-format');
var rowCommand = $('#row-node-input-command');
fieldFunction.change(function() {
var curVal = fieldFunction.val();
console.log('fieldFunction', curVal);
switch (curVal) {
case 'request':
case 'poke':
case 'advise':
case 'advise-stop':
rowTopic.show();
rowItem.show();
rowFormat.show();
rowCommand.hide();
break;
case 'execute':
rowTopic.show();
rowItem.hide();
rowFormat.hide();
rowCommand.show();
break;
case 'advise-stop-all':
default:
rowTopic.hide();
rowItem.hide();
rowFormat.hide();
rowCommand.hide();
}
});
fieldFunction.change();
},
oneditsave: function() {
var func = $('#node-input-function').val();
this.outputs = func == 'advise' ? 2 : 1;
}
});
</script>