1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Update mqtt nodes for v5

This commit is contained in:
Nick O'Leary 2021-02-25 15:49:56 +00:00
parent 16088b8a08
commit 255b8f2005
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
4 changed files with 586 additions and 449 deletions

View File

@ -11,9 +11,6 @@
limitations under the License. limitations under the License.
--> -->
<style> <style>
.form-row label:first-child {
width: 125px;
}
.mqtt-form-row-cols2 > input.mqtt-form-row-col1 { .mqtt-form-row-cols2 > input.mqtt-form-row-col1 {
width: calc(35% - 75px); width: calc(35% - 75px);
@ -35,7 +32,9 @@
width: calc(35% - 75px); width: calc(35% - 75px);
display: inline-block; display: inline-block;
} }
.form-row.mqtt5-out > label {
width: 130px;
}
.form-row.mqtt-flags-row > label { .form-row.mqtt-flags-row > label {
vertical-align: top; vertical-align: top;
} }
@ -46,9 +45,7 @@
.form-row.mqtt-flags-row > .mqtt-flags > .mqtt-flag > label { .form-row.mqtt-flags-row > .mqtt-flags > .mqtt-flag > label {
display: block; display: block;
padding-left: 15px; width: 100%;
text-indent: -15px;
width: 70%;
} }
.form-row.mqtt-flags-row > .mqtt-flags > .mqtt-flag > label > input { .form-row.mqtt-flags-row > .mqtt-flags > .mqtt-flag > label > input {
position: relative; position: relative;
@ -86,17 +83,6 @@
<option value="base64" data-i18n="mqtt.output.base64"></option> <option value="base64" data-i18n="mqtt.output.base64"></option>
</select> </select>
</div> </div>
<!-- FUTURE
<div class="form-row mqtt5">
<label for="node-input-userProperties"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.userProperties"></span></label>
<input id="node-input-userPropertiesType" type="hidden">
<input type="text" id="node-input-userProperties" style="width: 70%;" data-i18n="[placeholder]mqtt.label.userProperties" placeholder="">
</div> -->
<!-- FUTURE
<div class="form-row mqtt5">
<label for="node-input-subscriptionIdentifier" class="mqtt-form-row-col1"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.subscriptionIdentifier"></span></label>
<input type="number" min="0" max="268435455" id="node-input-subscriptionIdentifier" class="mqtt-form-row-col1" >
</div> -->
<div class="form-row mqtt-flags-row mqtt5"> <div class="form-row mqtt-flags-row mqtt5">
<label for="node-input-nl" ><i class="fa fa-flag"></i> <span data-i18n="mqtt.label.flags">Flags</span></label> <label for="node-input-nl" ><i class="fa fa-flag"></i> <span data-i18n="mqtt.label.flags">Flags</span></label>
<div class="mqtt-flags"> <div class="mqtt-flags">
@ -115,8 +101,8 @@
</div> </div>
</div> </div>
<div class="form-row mqtt5"> <div class="form-row mqtt5">
<label for="node-input-rh" ><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.rh"></span></label> <label for="node-input-rh" style="width:100%"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.rh"></span></label>
<select id="node-input-rh" style="width:70%;"> <select id="node-input-rh" style="margin-left: 104px; width: 70%">
<option value="0" data-i18n="mqtt.label.rh0"></option> <option value="0" data-i18n="mqtt.label.rh0"></option>
<option value="1" data-i18n="mqtt.label.rh1"></option> <option value="1" data-i18n="mqtt.label.rh1"></option>
<option value="2" data-i18n="mqtt.label.rh2"></option> <option value="2" data-i18n="mqtt.label.rh2"></option>
@ -128,58 +114,6 @@
</div> </div>
</script> </script>
<script type="text/javascript">
RED.nodes.registerType('mqtt in',{
category: 'network',
defaults: {
name: {value:""},
topic: {value:"",required:true,validate: RED.validators.regex(/^(#$|(\+|[^+#]*)(\/(\+|[^+#]*))*(\/(\+|#|[^+#]*))?$)/)},
qos: {value: "2"},
datatype: {value:"auto",required:true},
broker: {type:"mqtt-broker", required:true},
// userProperties: {value:"userProperties"},
// userPropertiesType: {value:"none"},
// subscriptionIdentifier: {value:0},
nl: {value:false},
rap: {value:true},
rh: {value:0},
},
color:"#d8bfd8",
inputs:0,
outputs:1,
icon: "bridge.svg",
label: function() {
return this.name||this.topic||"mqtt";
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
$("#node-input-broker").change(function(d){
var confNode = RED.nodes.node($("#node-input-broker").val());
var v5 = confNode && confNode.protocolVersion == "5";
if(v5) {
$("div.form-row.mqtt5").show();
} else {
$("div.form-row.mqtt5").hide();
}
});
if (this.qos === undefined) {
$("#node-input-qos").val("2");
}
if (this.datatype === undefined) {
$("#node-input-datatype").val("auto");
}
// FUTURE
// $("#node-input-userProperties").typedInput({
// default: "none",
// types:[{ value: 'none', label: 'None', hasValue: false },'flow','global','json'],
// typeField: $("#node-input-userPropertiesType")
// });
}
});
</script>
<script type="text/html" data-template-name="mqtt out"> <script type="text/html" data-template-name="mqtt out">
<div class="form-row"> <div class="form-row">
<label for="node-input-broker"><i class="fa fa-globe"></i> <span data-i18n="mqtt.label.broker"></span></label> <label for="node-input-broker"><i class="fa fa-globe"></i> <span data-i18n="mqtt.label.broker"></span></label>
@ -206,50 +140,28 @@
<option value="true" data-i18n="mqtt.true"></option> <option value="true" data-i18n="mqtt.true"></option>
</select> </select>
</div> </div>
<div class="form-row mqtt5"> <div class="form-row mqtt5 mqtt5-out">
<label for="node-input-userProperties"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.userProperties"></span></label> <label for="node-input-userProps"><span data-i18n="mqtt.label.userProperties"></span></label>
<input id="node-input-userPropertiesType" type="hidden"> <input type="text" id="node-input-userProps" style="width: calc(100% - 166px);">
<input type="text" id="node-input-userProperties" style="width: 70%;" data-i18n="[placeholder]mqtt.label.userProperties" placeholder="">
</div> </div>
<div class="form-row mqtt5"> <div class="form-row mqtt5 mqtt5-out">
<label for="node-input-responseTopic"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.responseTopic"></span></label> <label for="node-input-respTopic"><span data-i18n="mqtt.label.responseTopic"></span></label>
<input id="node-input-responseTopicType" type="hidden"> <input type="text" id="node-input-respTopic" style="width: calc(100% - 166px);">
<input type="text" id="node-input-responseTopic" style="width: 70%;" data-i18n="[placeholder]mqtt.label.responseTopic" placeholder="">
</div> </div>
<div class="form-row mqtt5"> <div class="form-row mqtt5 mqtt5-out">
<label for="node-input-correlationData"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.correlationData"></span></label> <label for="node-input-correl"><span data-i18n="mqtt.label.correlationData"></span></label>
<input id="node-input-correlationDataType" type="hidden"> <input type="text" id="node-input-correl" style="width: calc(100% - 166px);">
<input type="text" id="node-input-correlationData" style="width: 70%;" data-i18n="[placeholder]mqtt.label.correlationData" placeholder="">
</div> </div>
<div class="form-row mqtt5"> <div class="form-row mqtt5 mqtt5-out">
<label for="node-input-contentType"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.contentType"></span></label> <label for="node-input-contentType"><span data-i18n="mqtt.label.contentType"></span></label>
<input id="node-input-contentTypeType" type="hidden"> <input type="text" id="node-input-contentType" style="width: calc(100% - 166px);">
<input type="text" id="node-input-contentType" style="width: 70%;" data-i18n="[placeholder]mqtt.label.contentType" placeholder="">
</div> </div>
<div class="form-row mqtt-form-row-cols2 mqtt5"> <div class="form-row mqtt-form-row-cols2 mqtt5 mqtt5-out">
<label for="node-input-messageExpiryInterval" class="mqtt-form-row-col1"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.messageExpiryInterval"></span></label> <label for="node-input-expiry" class="mqtt-form-row-col1"><span data-i18n="mqtt.label.expiry"></span></label>
<input id="node-input-messageExpiryIntervalType" type="hidden"> <input id="node-input-expiry" style="width: calc(100% - 166px);" class="mqtt-form-row-col1" >
<input id="node-input-messageExpiryInterval" style="width: 70%;" class="mqtt-form-row-col1" >
<!-- FUTURE
<label for="node-input-topicAlias" class="mqtt-form-row-col2"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.topicAlias">Alias</span></label>
<input type="number" min="0" id="node-input-topicAlias" class="mqtt-form-row-col2" > -->
</div> </div>
<!-- FUTURE
<div class="form-row mqtt-form-row-cols2 mqtt5">
<label for="node-input-subscriptionIdentifier" class="mqtt-form-row-col1"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.subscriptionIdentifier"></span></label>
<input type="number" min="0" max="268435455" id="node-input-subscriptionIdentifier" class="mqtt-form-row-col1" >
<label for="node-input-payloadFormatIndicator" class="mqtt-form-row-col2"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.payloadFormatIndicator"></span></label>
<select id="node-input-payloadFormatIndicator" class="mqtt-form-row-col2" >
<option value=""></option>
<option value="false" data-i18n="mqtt.label.payloadFormatIndicatorFalse"></option>
<option value="true" data-i18n="mqtt.label.payloadFormatIndicatorTrue"></option>
</select>
</div> -->
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label> <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name"> <input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
@ -257,149 +169,6 @@
<div class="form-tips"><span data-i18n="mqtt.tip"></span></div> <div class="form-tips"><span data-i18n="mqtt.tip"></span></div>
</script> </script>
<script type="text/javascript">
RED.nodes.registerType('mqtt out',{
category: 'network',
defaults: {
name: {value:""},
topic: {value:""},
qos: {value:""},
retain: {value:""},
responseTopic: {value:"responseTopic"},
responseTopicType: {value:'none'},
contentType: {value:"contentType"},
contentTypeType: {value:'none'},
userProperties: {value:'userProperties'},
userPropertiesType: {value:'none'},
correlationData: {value:'correlationData'},
correlationDataType: {value:'none'},
messageExpiryInterval: {value:"messageExpiryInterval"},
messageExpiryIntervalType: {value:'none'},
// FUTURE topicAlias: {value:0},
// FUTURE payloadFormatIndicator: {value:false},
// FUTURE subscriptionIdentifier: {value:0},
broker: {type:"mqtt-broker", required:true}
},
color:"#d8bfd8",
inputs:1,
outputs:0,
icon: "bridge.svg",
align: "right",
label: function() {
return this.name||this.topic||"mqtt";
// FUTURE return this.name||this.topic||(this.topicAlias ? "@"+this.topicAlias : "mqtt");
},
oneditprepare: function() {
var typedInputNoneOpt = { value: 'none', label: 'None', hasValue: false };
function showHideDynamicFields() {
var confNode = RED.nodes.node($("#node-input-broker").val());
var v5 = confNode && confNode.protocolVersion == "5";
if(v5) {
$("div.form-row.mqtt5").show();
} else {
$("div.form-row.mqtt5").hide();
}
var t = $("#node-input-responseTopic").typedInput("type");
if (t == 'none') {
$("#node-input-correlationData").parent().hide();
} else {
$("#node-input-correlationData").parent().show();
}
}
$("#node-input-broker").change(function(d){
showHideDynamicFields();
});
var responseTopicTI = $("#node-input-responseTopic").typedInput({
default: 'none',
types: [typedInputNoneOpt, 'msg', 'flow', 'global', 'str'],
typeField: $("#node-input-responseTopicType")
});
var correlationDataTI = $("#node-input-correlationData").typedInput({
default: 'none',
types: [typedInputNoneOpt, 'msg', 'flow', 'global', 'bin'],
typeField: $("#node-input-correlationDataType")
});
//show / hide correlation data depending on responseTopic
responseTopicTI.on("change", function() {
showHideDynamicFields();
});
responseTopicTI.triggerHandler("change");
$("#node-input-userProperties").typedInput({
default: 'none',
types: [typedInputNoneOpt, 'msg', 'flow', 'global', 'json'],
typeField: $("#node-input-userPropertiesType")
});
$("#node-input-messageExpiryInterval").typedInput({
default: 'none',
types: [typedInputNoneOpt, 'msg', 'flow', 'global', 'num'],
typeField: $("#node-input-messageExpiryIntervalType")
});
var makeTypedInputOpt = function(value, label, tooltip){
return {
label: label,
value: value || label,
title: tooltip,
multiple: true
}
}
//TODO: i18n
var commonOpts = [
makeTypedInputOpt("application/gzip", "application/gzip", "GZip Compressed Archive"),
makeTypedInputOpt("application/json", "application/json", "JSON format"),
makeTypedInputOpt("application/octet-stream", "application/octet-stream", "Any kind of binary data"),
makeTypedInputOpt("application/ogg", "application/ogg", "OGG"),
makeTypedInputOpt("application/pdf", "application/pdf", "Adobe Portable Document Format (PDF)"),
makeTypedInputOpt("application/zip", "application/zip", "ZIP archive"),
makeTypedInputOpt("audio/aac", "audio/aac", "AAC audio"),
makeTypedInputOpt("audio/midi", "audio/midi", "Musical Instrument Digital Interface (MIDI)"),
makeTypedInputOpt("audio/x-midi", "audio/x-midi", "Musical Instrument Digital Interface (MIDI)"),
makeTypedInputOpt("audio/mpeg", "audio/mpeg", "MP3 audio"),
makeTypedInputOpt("audio/ogg", "audio/ogg", "OGG audio"),
makeTypedInputOpt("audio/wav", "audio/wav", "Waveform Audio Format"),
makeTypedInputOpt("audio/webm", "audio/webm", "WEBM audio"),
makeTypedInputOpt("image/bmp", "image/bmp", "Windows OS/2 Bitmap Graphics"),
makeTypedInputOpt("image/gif", "image/gif", "Graphics Interchange Format (GIF)"),
makeTypedInputOpt("image/jpeg", "image/jpeg", "JPEG images"),
makeTypedInputOpt("image/png", "image/png", "Portable Network Graphics"),
makeTypedInputOpt("image/tiff", "image/tiff", "Tagged Image File Format (TIFF)"),
makeTypedInputOpt("image/webp", "image/webp", "WEBP image"),
makeTypedInputOpt("text/csv", "text/csv", "Comma-separated values (CSV)"),
makeTypedInputOpt("text/html", "text/html", "HyperText Markup Language (HTML)"),
makeTypedInputOpt("text/plain", "text/plain", "Text, (generally ASCII or ISO 8859-n)"),
makeTypedInputOpt("video/mpeg", "video/mpeg", "MPEG Video"),
makeTypedInputOpt("video/ogg", "video/ogg", "OGG video"),
makeTypedInputOpt("video/webm", "video/webm", "WEBM video"),
];
$("#node-input-contentType").typedInput({
default: 'none',
types: [
typedInputNoneOpt,
{
value: "preset",
label: "Preset",
title: "Preset Content-Types",
icon: "fa fa-list",
showLabel: false,
multiple: false,
options: commonOpts,
default: "application/json"
}, 'msg', 'flow', 'global', 'str'],
typeField: $("#node-input-contentTypeType")
});
},
labelStyle: function() {
return this.name?"node_label_italic":"";
}
});
</script>
<script type="text/html" data-template-name="mqtt-broker"> <script type="text/html" data-template-name="mqtt-broker">
<div class="form-row"> <div class="form-row">
<label for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label> <label for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
@ -412,35 +181,14 @@
<div id="mqtt-broker-tab-connection" style="display:none"> <div id="mqtt-broker-tab-connection" style="display:none">
<div class="form-row node-input-broker"> <div class="form-row node-input-broker">
<label for="node-config-input-broker"><i class="fa fa-globe"></i> <span data-i18n="mqtt.label.broker"></span></label> <label for="node-config-input-broker"><i class="fa fa-globe"></i> <span data-i18n="mqtt.label.broker"></span></label>
<input type="text" id="node-config-input-broker" style="width:40%;" data-i18n="[placeholder]mqtt.label.example"> <input type="text" id="node-config-input-broker" style="width: calc(100% - 300px);" data-i18n="[placeholder]mqtt.label.example">
<label for="node-config-input-port" style="margin-left:20px; width:43px; "> <span data-i18n="mqtt.label.port"></span></label> <label for="node-config-input-port" style="margin-left:20px; width:43px; "> <span data-i18n="mqtt.label.port"></span></label>
<input type="text" id="node-config-input-port" data-i18n="[placeholder]mqtt.label.port" style="width:55px"> <input type="text" id="node-config-input-port" data-i18n="[placeholder]mqtt.label.port" style="width:55px">
</div> </div>
<div class="form-row"> <div class="form-row" style="height: 34px;">
<input type="checkbox" id="node-config-input-usetls" style="display: inline-block; width: auto; vertical-align: top;"> <input type="checkbox" id="node-config-input-usetls" style="height: 34px; margin: 0 0 0 104px; display: inline-block; width: auto; vertical-align: top;">
<label for="node-config-input-usetls" style="width: auto" data-i18n="mqtt.label.use-tls"></label> <label for="node-config-input-usetls" style="width: 80px; line-height: 34px;" data-ai18n="mqtt.label.use-tls">Use TLS</label>
<div id="node-config-row-tls" class="hide"> <span id="node-config-row-tls" class="hide"><input style="width: 320px;" type="text" id="node-config-input-tls"></span>
<label style="width: auto; margin-left: 20px; margin-right: 10px;" for="node-config-input-tls"><span data-i18n="mqtt.label.tls-config"></span></label><input style="width: 300px;" type="text" id="node-config-input-tls">
</div>
</div>
<div class="form-row">
<label for="node-config-input-clientid"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.clientid"></span></label>
<input type="text" id="node-config-input-clientid" data-i18n="[placeholder]mqtt.placeholder.clientid">
</div>
<div class="form-row">
<label for="node-config-input-keepalive" style="width: auto"><i class="fa fa-clock-o"></i> <span data-i18n="mqtt.label.keepalive"></span></label>
<input type="text" id="node-config-input-keepalive" style="width: 50px">
</div>
<div class="form-row mqtt-form-row-cols2">
<label for="node-config-input-cleansession" class="mqtt-form-row-col1"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.session"></span>Session</label>
<div class="mqtt-flag mqtt-form-row-col1" style="display: inline-block;width: calc(35% - 75px);">
<label for="node-config-input-cleansession" style="display: block; padding-left: 15px; text-indent: -15px;">
<input type="checkbox" id="node-config-input-cleansession" style="position: relative;vertical-align: bottom; top: -2px; width: 15px;height: 15px;">
<span data-i18n="mqtt.label.cleansession"></span>
</label>
</div>
<label for="node-config-input-sessionExpiryInterval" class="mqtt-form-row-col2 mqtt5 sessionExpiryInterval"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.sessionExpiryInterval"></span></label>
<input type="number" min="0" id="node-config-input-sessionExpiryInterval" class="mqtt-form-row-col2 mqtt5 sessionExpiryInterval" >
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-config-input-protocolVersion"><i class="fa fa-cog"></i> <span data-i18n="mqtt.label.protocolVersion"></span></label> <label for="node-config-input-protocolVersion"><i class="fa fa-cog"></i> <span data-i18n="mqtt.label.protocolVersion"></span></label>
@ -450,24 +198,34 @@
<option value="5" data-i18n="mqtt.label.protocolVersion5"></option> <option value="5" data-i18n="mqtt.label.protocolVersion5"></option>
</select> </select>
</div> </div>
<!-- FUTURE <div class="form-row">
<div class="form-row mqtt5"> <label for="node-config-input-clientid"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.clientid"></span></label>
<label for="node-config-input-userProperties"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.userProperties"></span></label> <input type="text" id="node-config-input-clientid" data-i18n="[placeholder]mqtt.placeholder.clientid">
<input id="node-config-input-userPropertiesType" type="hidden"> </div>
<input type="text" id="node-config-input-userProperties" style="width: 70%;" data-i18n="[placeholder]mqtt.label.userProperties" placeholder=""> <div class="form-row">
<label for="node-config-input-keepalive"><i class="fa fa-heartbeat"></i> <span data-i18n="mqtt.label.keepalive"></span></label>
<input type="number" min="0" id="node-config-input-keepalive" style="width: 100px">
</div>
<div class="form-row" style="margin-bottom:0">
<label style="vertical-align:top;"><i class="fa fa-info"></i> Session</label>
<div style="display: inline-block; width:calc(100% - 110px)">
<div class="form-row">
<label for="node-config-input-cleansession" style="width: auto;">
<input type="checkbox" id="node-config-input-cleansession" style="position: relative;vertical-align: bottom; top: -2px; width: 15px;height: 15px;">
<span id="node-config-input-cleansession-label" data-i18n="mqtt.label.cleansession"></span>
</label>
</div> </div>
<div class="form-row mqtt5"> <div class="form-row mqtt5">
<label for="node-config-input-topicAliasMaximum"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.topicAliasMaximum"></span></label> <label style="width:auto" for="node-config-input-sessionExpiry"><span data-i18n="mqtt.label.sessionExpiry"></span></label>
<input type="number" min="0" id="node-config-input-topicAliasMaximum"> <input type="number" min="0" id="node-config-input-sessionExpiry" style="width: 100px" >
</div>
</div>
</div> </div>
<div class="form-row mqtt5"> <div class="form-row mqtt5">
<label for="node-config-input-maximumPacketSize" ><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.maximumPacketSize"></span></label> <label style="width: 125px;" for="node-config-input-userProps"><span data-i18n="mqtt.label.userProperties"></span></label>
<input type="number" min="0" id="node-config-input-maximumPacketSize"> <input type="text" id="node-config-input-userProps" style="width: calc(100% - 166px);">
</div> </div>
<div class="form-row mqtt5"> <br>
<label for="node-config-input-receiveMaximum" ><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.receiveMaximum"></span></label>
<input type="number" min="0" id="node-config-input-receiveMaximum">
</div> -->
</div> </div>
<div id="mqtt-broker-tab-security" style="display:none"> <div id="mqtt-broker-tab-security" style="display:none">
<div class="form-row"> <div class="form-row">
@ -504,6 +262,26 @@
<option value="2">2</option> <option value="2">2</option>
</select> </select>
</div> </div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-birth-contentType" data-i18n="mqtt.label.contentType"></label>
<input type="text" style="width:calc(100% - 200px);" id="node-config-input-birth-contentType">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-birth-props" data-i18n="mqtt.label.userProperties"></label>
<input type="text" style="width:calc(100% - 200px);" id="node-config-input-birth-props">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-birth-respTopic"><span data-i18n="mqtt.label.responseTopic"></span></label>
<input type="text" id="node-config-input-birth-respTopic" style="width: calc(100% - 200px);">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-birth-correl"><span data-i18n="mqtt.label.correlationData"></span></label>
<input type="text" id="node-config-input-birth-correl" style="width: calc(100% - 200px);">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-birth-expiry"><span data-i18n="mqtt.label.expiry"></span></label>
<input id="node-config-input-birth-expiry" style="width: calc(100% - 200px);">
</div>
</div> </div>
</div> </div>
<div id="mqtt-broker-section-close"> <div id="mqtt-broker-section-close">
@ -530,6 +308,26 @@
<option value="2">2</option> <option value="2">2</option>
</select> </select>
</div> </div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-close-contentType" data-i18n="mqtt.label.contentType"></label>
<input type="text" style="width:calc(100% - 200px);" id="node-config-input-close-contentType">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-close-props" data-i18n="mqtt.label.userProperties"></label>
<input type="text" style="width:calc(100% - 200px);" id="node-config-input-close-props">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-close-respTopic"><span data-i18n="mqtt.label.responseTopic"></span></label>
<input type="text" id="node-config-input-close-respTopic" style="width: calc(100% - 200px);">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-close-correl"><span data-i18n="mqtt.label.correlationData"></span></label>
<input type="text" id="node-config-input-close-correl" style="width: calc(100% - 200px);">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-close-expiry"><span data-i18n="mqtt.label.expiry"></span></label>
<input id="node-config-input-close-expiry" style="width: calc(100% - 200px);">
</div>
</div> </div>
</div> </div>
<div id="mqtt-broker-section-will"> <div id="mqtt-broker-section-will">
@ -556,6 +354,30 @@
<option value="2">2</option> <option value="2">2</option>
</select> </select>
</div> </div>
<div class="form-row mqtt5">
<label>Delay</label>
<input type="number" min="0" id="node-config-input-will-delay" style="width: 100px" >
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-will-contentType" data-i18n="mqtt.label.contentType"></label>
<input type="text" style="width:calc(100% - 200px);" id="node-config-input-will-contentType">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-will-props" data-i18n="mqtt.label.userProperties"></label>
<input type="text" style="width:calc(100% - 200px);" id="node-config-input-will-props">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-will-respTopic"><span data-i18n="mqtt.label.responseTopic"></span></label>
<input type="text" id="node-config-input-will-respTopic" style="width: calc(100% - 200px);">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-will-correl"><span data-i18n="mqtt.label.correlationData"></span></label>
<input type="text" id="node-config-input-will-correl" style="width: calc(100% - 200px);">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-will-expiry"><span data-i18n="mqtt.label.expiry"></span></label>
<input id="node-config-input-will-expiry" style="width: calc(100% - 200px);">
</div>
</div> </div>
</div> </div>
</div> </div>
@ -563,6 +385,40 @@
</script> </script>
<script type="text/javascript"> <script type="text/javascript">
(function() {
var typedInputNoneOpt = { value: 'none', label: '', hasValue: false };
var makeTypedInputOpt = function(value){
return {
value: value,
label:value,
hasValue: false
}
}
var contentTypeOpts = [
typedInputNoneOpt,
makeTypedInputOpt("application/json"),
makeTypedInputOpt("application/octet-stream"),
makeTypedInputOpt("text/csv"),
makeTypedInputOpt("text/html"),
makeTypedInputOpt("text/plain"),
{value:"other", label:""}
];
function getDefaultContentType(value) {
var defaultContentType;
var matchedContentType = contentTypeOpts.filter(function(v) {
return v.value === value;
})
if (matchedContentType.length > 0) {
defaultContentType = matchedContentType[0].value;
}
if (value && !defaultContentType) {
defaultContentType = 'other';
}
return defaultContentType || 'none'
}
RED.nodes.registerType('mqtt-broker',{ RED.nodes.registerType('mqtt-broker',{
category: 'config', category: 'config',
defaults: { defaults: {
@ -588,20 +444,18 @@
birthQos: {value:"0"}, birthQos: {value:"0"},
birthRetain: {value:false}, birthRetain: {value:false},
birthPayload: {value:""}, birthPayload: {value:""},
birthMsg: { value: {}},
closeTopic: {value:""}, closeTopic: {value:""},
closeQos: {value:"0"}, closeQos: {value:"0"},
closeRetain: {value:false}, closeRetain: {value:false},
closePayload: {value:""}, closePayload: {value:""},
closeMsg: { value: {}},
willTopic: {value:""}, willTopic: {value:""},
willQos: {value:"0"}, willQos: {value:"0"},
willRetain: {value:false}, willRetain: {value:false},
willPayload: {value:""}, willPayload: {value:""},
sessionExpiryInterval: {value:0}, willMsg: { value: {}},
// FUTURE topicAliasMaximum: {value:0}, sessionExpiry: {value:0}
// FUTURE maximumPacketSize: {value:0},
// FUTURE receiveMaximum: {value:0},
// FUTURE userPropertiesType: {value:"json"},
// FUTURE userProperties: {value:"{}"},
}, },
credentials: { credentials: {
user: {type:"text"}, user: {type:"text"},
@ -643,8 +497,8 @@
label: this._("mqtt.tabs-label.messages") label: this._("mqtt.tabs-label.messages")
}); });
function setUpSection(sectionId, isExpanded) { function setUpSection(sectionId, v5Opts, isExpanded) {
var birthMessageSection = $(sectionId); var birthMessageSection = $("#mqtt-broker-section-"+sectionId);
var paletteHeader = birthMessageSection.find('.red-ui-palette-header'); var paletteHeader = birthMessageSection.find('.red-ui-palette-header');
var twistie = paletteHeader.find('i'); var twistie = paletteHeader.find('i');
var sectionContent = birthMessageSection.find('.section-content'); var sectionContent = birthMessageSection.find('.section-content');
@ -659,6 +513,27 @@
toggleSection(!isExpanded); toggleSection(!isExpanded);
}); });
toggleSection(isExpanded); toggleSection(isExpanded);
$("#node-config-input-"+sectionId+"-contentType").val(v5Opts?v5Opts.contentType:"").typedInput({
default: getDefaultContentType(v5Opts?v5Opts.contentType:""),
types: contentTypeOpts,
});
$("#node-config-input-"+sectionId+"-props").val(v5Opts?v5Opts.userProps:"").typedInput({
default: !(v5Opts?v5Opts.userProps:null)? 'none':'json',
types: [typedInputNoneOpt, 'json'],
});
$("#node-config-input-"+sectionId+"-respTopic").val(v5Opts?v5Opts.respTopic:"").typedInput({
default: !(v5Opts?v5Opts.respTopic:null)? 'none':'str',
types: [typedInputNoneOpt, 'str'],
});
$("#node-config-input-"+sectionId+"-correl").val(v5Opts?v5Opts.correl:"").typedInput({
default: !(v5Opts?v5Opts.correl:null)? 'none':'str',
types: [typedInputNoneOpt, 'str'],
});
$("#node-config-input-"+sectionId+"-expiry").val(v5Opts?v5Opts.expiry:"").typedInput({
default: !(v5Opts?v5Opts.expiry:null)? 'none':'num',
types: [typedInputNoneOpt, 'num'],
});
} }
// show first section if none are set so the user gets the idea // show first section if none are set so the user gets the idea
@ -666,9 +541,13 @@
|| this.willTopic === "" || this.willTopic === ""
&& this.birthTopic === "" && this.birthTopic === ""
&& this.closeTopic == ""; && this.closeTopic == "";
setUpSection('#mqtt-broker-section-birth', showBirthSection); setUpSection('birth', this.birthMsg, showBirthSection);
setUpSection('#mqtt-broker-section-close', this.closeTopic !== ""); setUpSection('close', this.closeMsg, this.closeTopic !== "");
setUpSection('#mqtt-broker-section-will', this.willTopic !== ""); setUpSection('will', this.willMsg, this.willTopic !== "");
if (this.willMsg) {
$("#node-config-input-will-delay").val(this.willMsg.delay);
}
setTimeout(function() { tabs.resize(); },0); setTimeout(function() { tabs.resize(); },0);
if (typeof this.cleansession === 'undefined') { if (typeof this.cleansession === 'undefined') {
@ -686,30 +565,21 @@
if (typeof this.protocolVersion === 'undefined') { if (typeof this.protocolVersion === 'undefined') {
this.protocolVersion = 4; this.protocolVersion = 4;
} }
function updateSessionExpiryIntervalVisibility() { $("#node-config-input-protocolVersion").on("change", function() {
var hide = ($("#node-config-input-cleansession").is(":checked") || $("#node-config-input-protocolVersion").val() != "5");
if(hide) {
$(".sessionExpiryInterval").hide();
} else {
$(".sessionExpiryInterval").show();
}
}
$("#node-config-input-protocolVersion").change(function(){
var v5 = $("#node-config-input-protocolVersion").val() == "5"; var v5 = $("#node-config-input-protocolVersion").val() == "5";
if(v5) { if(v5) {
$("#node-config-input-cleansession-label").text(RED._("node-red:mqtt.label.cleanstart"))
$("div.form-row.mqtt5").show(); $("div.form-row.mqtt5").show();
} else { } else {
$("#node-config-input-cleansession-label").text(RED._("node-red:mqtt.label.cleansession"))
$("div.form-row.mqtt5").hide(); $("div.form-row.mqtt5").hide();
} }
updateSessionExpiryIntervalVisibility();
}); });
$("#node-config-input-protocolVersion").val(this.protocolVersion); $("#node-config-input-protocolVersion").val(this.protocolVersion);
// FUTURE $("#node-config-input-userProps").typedInput({
// $("#node-config-input-userProperties").typedInput({ default: !this.userProps ? 'none':'json',
// default: "json", types: [typedInputNoneOpt, 'json']
// types:['json'], });
// typeField: $("#node-config-input-userPropertiesType")
// });
if (typeof this.keepalive === 'undefined') { if (typeof this.keepalive === 'undefined') {
this.keepalive = 15; this.keepalive = 15;
$("#node-config-input-keepalive").val(this.keepalive); $("#node-config-input-keepalive").val(this.keepalive);
@ -727,6 +597,7 @@
$("#node-config-input-willQos").val("0"); $("#node-config-input-willQos").val("0");
} }
function updateTLSOptions() { function updateTLSOptions() {
if ($("#node-config-input-usetls").is(':checked')) { if ($("#node-config-input-usetls").is(':checked')) {
$("#node-config-row-tls").show(); $("#node-config-row-tls").show();
@ -745,8 +616,7 @@
} else { } else {
$("#node-config-input-clientid").attr("placeholder",node._("mqtt.placeholder.clientid-nonclean")); $("#node-config-input-clientid").attr("placeholder",node._("mqtt.placeholder.clientid-nonclean"));
} }
updateSessionExpiryIntervalVisibility(); $("#node-config-input-clientid").trigger("change");
$("#node-config-input-clientid").change();
} }
setTimeout(updateClientId,0); setTimeout(updateClientId,0);
$("#node-config-input-cleansession").on("click",function() { $("#node-config-input-cleansession").on("click",function() {
@ -773,12 +643,198 @@
updatePortEntry(); updatePortEntry();
}); });
setTimeout(updatePortEntry,50); setTimeout(updatePortEntry,50);
setTimeout(function() {
$("#node-config-input-protocolVersion").trigger("change");
},50);
}, },
oneditsave: function() { oneditsave: function() {
if (!$("#node-config-input-usetls").is(':checked')) { if (!$("#node-config-input-usetls").is(':checked')) {
$("#node-config-input-tls").val(""); $("#node-config-input-tls").val("");
} }
var v5 = $("#node-config-input-protocolVersion").val() == "5";
function saveV5Message(section) {
var msg = {};
if ($("#node-config-input-"+section+"Topic").val().trim().length > 0) {
var contentType = $("#node-config-input-"+section+"-contentType").val().trim();
if (contentType === '') {
contentType = $("#node-config-input-"+section+"-contentType").typedInput('type');
if (contentType === 'none' || contentType === 'other') {
contentType = "";
}
}
if (contentType) {
msg.contentType = contentType;
}
var props = $("#node-config-input-"+section+"-props").val().trim();
if (props) {
msg.userProps = props;
}
var resp = $("#node-config-input-"+section+"-respTopic").val().trim();
if (props) {
msg.respTopic = resp;
}
var correl = $("#node-config-input-"+section+"-correl").val().trim();
if (correl) {
msg.correl = correl;
}
var expiry = $("#node-config-input-"+section+"-expiry").val().trim();
if (expiry) {
msg.expiry = expiry;
}
}
return msg;
}
if (v5) {
this.birthMsg = saveV5Message("birth");
this.closeMsg = saveV5Message("close");
this.willMsg = saveV5Message("will");
var willDelay = $("#node-config-input-will-delay").val();
if (willDelay) {
this.willMsg.delay = willDelay;
}
} else {
this.willMsg = {};
this.birthMsg = {};
this.closeMsg = {};
}
} }
}); });
RED.nodes.registerType('mqtt in',{
category: 'network',
defaults: {
name: {value:""},
topic: {value:"",required:true,validate: RED.validators.regex(/^(#$|(\+|[^+#]*)(\/(\+|[^+#]*))*(\/(\+|#|[^+#]*))?$)/)},
qos: {value: "2"},
datatype: {value:"auto",required:true},
broker: {type:"mqtt-broker", required:true},
// subscriptionIdentifier: {value:0},
nl: {value:false},
rap: {value:true},
rh: {value:0},
},
color:"#d8bfd8",
inputs:0,
outputs:1,
icon: "bridge.svg",
label: function() {
return this.name||this.topic||"mqtt";
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
$("#node-input-broker").on("change",function(d){
var confNode = RED.nodes.node($("#node-input-broker").val());
var v5 = confNode && confNode.protocolVersion == "5";
if(v5) {
$("div.form-row.mqtt5").show();
} else {
$("div.form-row.mqtt5").hide();
}
});
if (this.qos === undefined) {
$("#node-input-qos").val("2");
}
if (this.datatype === undefined) {
$("#node-input-datatype").val("auto");
}
}
});
RED.nodes.registerType('mqtt out',{
category: 'network',
defaults: {
name: {value:""},
topic: {value:""},
qos: {value:""},
retain: {value:""},
respTopic: {value:""},
contentType: {value:""},
userProps: {value:''},
correl: {value:''},
expiry: {value:''},
broker: {type:"mqtt-broker", required:true}
},
color:"#d8bfd8",
inputs:1,
outputs:0,
icon: "bridge.svg",
align: "right",
label: function() {
return this.name||this.topic||"mqtt";
},
oneditprepare: function() {
var that = this;
function showHideDynamicFields() {
var confNode = RED.nodes.node($("#node-input-broker").val());
var v5 = confNode && confNode.protocolVersion == "5";
if(v5) {
$("div.form-row.mqtt5").show();
var t = $("#node-input-respTopic").typedInput("type");
if (t == 'none') {
$("#node-input-correl").parent().hide();
} else {
$("#node-input-correl").parent().show();
}
} else {
$("div.form-row.mqtt5").hide();
}
}
$("#node-input-broker").on("change",function(d){
showHideDynamicFields();
});
var respTopicTI = $("#node-input-respTopic").typedInput({
default: !this.respTopic ? 'none':'str',
types: [typedInputNoneOpt, 'str'],
});
var correlTI = $("#node-input-correl").typedInput({
default: !this.correl ? 'none':'str',
types: [typedInputNoneOpt, 'str']
});
//show / hide correlation data depending on respTopic
respTopicTI.on("change", showHideDynamicFields);
respTopicTI.triggerHandler("change");
$("#node-input-userProps").typedInput({
default: !this.userProps ? 'none':'json',
types: [typedInputNoneOpt, 'json'],
});
$("#node-input-expiry").typedInput({
default: !this.expiry ? 'none':'num',
types: [typedInputNoneOpt, 'num']
});
$("#node-input-contentType").on('change', function (event, type, value, urg) {
console.log(event);
console.log("ct change",type,value, urg);
}).typedInput({
default: getDefaultContentType(this.contentType),
types: contentTypeOpts
})
},
oneditsave: function() {
var contentType = $("#node-input-contentType").val().trim();
if (contentType === '') {
contentType = $("#node-input-contentType").typedInput('type');
if (contentType === 'none' || contentType === 'other') {
contentType = "";
}
}
$("#node-input-contentType").val(contentType)
},
labelStyle: function() {
return this.name?"node_label_italic":"";
}
});
})();
</script> </script>

View File

@ -14,8 +14,6 @@
* limitations under the License. * limitations under the License.
**/ **/
const { debug } = require("console");
module.exports = function(RED) { module.exports = function(RED) {
"use strict"; "use strict";
var mqtt = require("mqtt"); var mqtt = require("mqtt");
@ -162,7 +160,7 @@ module.exports = function(RED) {
this.protocolVersion = n.protocolVersion; this.protocolVersion = n.protocolVersion;
this.keepalive = n.keepalive; this.keepalive = n.keepalive;
this.cleansession = n.cleansession; this.cleansession = n.cleansession;
this.sessionExpiryInterval = n.sessionExpiryInterval; this.sessionExpiryInterval = n.sessionExpiry;
this.topicAliasMaximum = n.topicAliasMaximum; this.topicAliasMaximum = n.topicAliasMaximum;
this.maximumPacketSize = n.maximumPacketSize; this.maximumPacketSize = n.maximumPacketSize;
this.receiveMaximum = n.receiveMaximum; this.receiveMaximum = n.receiveMaximum;
@ -186,6 +184,20 @@ module.exports = function(RED) {
retain: n.birthRetain=="true"|| n.birthRetain===true, retain: n.birthRetain=="true"|| n.birthRetain===true,
//TODO: add payloadFormatIndicator, messageExpiryInterval, contentType, responseTopic, correlationData, userProperties //TODO: add payloadFormatIndicator, messageExpiryInterval, contentType, responseTopic, correlationData, userProperties
}; };
if (n.birthMsg) {
setStrProp(n.birthMsg, this.birthMessage, "contentType");
if(n.birthMsg.userProps && /^ *{/.test(n.birthMsg.userProps)) {
try {
this.birthMessage.userProperties = JSON.parse(n.birthMsg.userProps)
} catch(err) {}
}
n.birthMsg.responseTopic = n.birthMsg.respTopic;
setStrProp(n.birthMsg, this.birthMessage, "responseTopic");
n.birthMsg.correlationData = n.birthMsg.correl;
setBufferProp(n.birthMsg, this.birthMessage, "correlationData");
n.birthMsg.messageExpiryInterval = n.birthMsg.expiry
setIntProp(n.willMsg,this.birthMessage, "messageExpiryInterval")
}
} }
if (n.closeTopic) { if (n.closeTopic) {
@ -196,6 +208,20 @@ module.exports = function(RED) {
retain: n.closeRetain=="true"|| n.closeRetain===true, retain: n.closeRetain=="true"|| n.closeRetain===true,
//TODO: add payloadFormatIndicator, messageExpiryInterval, contentType, responseTopic, correlationData, userProperties //TODO: add payloadFormatIndicator, messageExpiryInterval, contentType, responseTopic, correlationData, userProperties
}; };
if (n.closeMsg) {
setStrProp(n.closeMsg, this.closeMessage, "contentType");
if(n.closeMsg.userProps && /^ *{/.test(n.closeMsg.userProps)) {
try {
this.closeMessage.userProperties = JSON.parse(n.closeMsg.userProps)
} catch(err) {}
}
n.closeMsg.responseTopic = n.closeMsg.respTopic;
setStrProp(n.closeMsg, this.closeMessage, "responseTopic");
n.closeMsg.correlationData = n.closeMsg.correl;
setBufferProp(n.closeMsg, this.closeMessage, "correlationData");
n.closeMsg.messageExpiryInterval = n.closeMsg.expiry
setIntProp(n.willMsg,this.closeMessage, "messageExpiryInterval")
}
} }
if (this.credentials) { if (this.credentials) {
@ -302,16 +328,14 @@ module.exports = function(RED) {
this.options.properties = {}; this.options.properties = {};
this.options.properties.requestResponseInformation = true; this.options.properties.requestResponseInformation = true;
this.options.properties.requestProblemInformation = true; this.options.properties.requestProblemInformation = true;
if(this.userProperties) { if(this.userProperties && /^ *{/.test(this.userProperties)) {
let userProperties = RED.util.evaluateNodeProperty(this.userProperties, this.userPropertiesType, this, {}); try {
setUserProperties(userProperties, this.options.properties); setUserProperties(JSON.parse(this.userProperties), this.options.properties);
} catch(err) {}
}
if (this.sessionExpiryInterval && this.sessionExpiryInterval !== "0") {
setIntProp(this,this.options.properties,"sessionExpiryInterval");
} }
setIntProp(this,this.options.properties,"sessionExpiryInterval", 0);
setIntProp(this,this.options.properties,"topicAliasMaximum", 0);
setIntProp(this,this.options.properties,"maximumPacketSize", 0);
setIntProp(this,this.options.properties,"receiveMaximum", 0);
setStrProp(this,this.options.properties,"authenticationMethod"); //TODO: authenticationMethod: the name of the authentication method used for extended authentication string,
setBufferProp(this,this.options.properties,"authenticationData"); //TODO: authenticationData: Binary Data containing authentication data
} }
if (this.usetls && n.tls) { if (this.usetls && n.tls) {
var tlsNode = RED.nodes.getNode(n.tls); var tlsNode = RED.nodes.getNode(n.tls);
@ -319,7 +343,6 @@ module.exports = function(RED) {
tlsNode.addTLSOptions(this.options); tlsNode.addTLSOptions(this.options);
} }
} }
// console.log(this.brokerurl,this.options);
// If there's no rejectUnauthorized already, then this could be an // If there's no rejectUnauthorized already, then this could be an
// old config where this option was provided on the broker node and // old config where this option was provided on the broker node and
@ -336,7 +359,28 @@ module.exports = function(RED) {
retain: n.willRetain=="true"|| n.willRetain===true, retain: n.willRetain=="true"|| n.willRetain===true,
//TODO: add willDelayInterval, payloadFormatIndicator, messageExpiryInterval, contentType, responseTopic, correlationData, userProperties //TODO: add willDelayInterval, payloadFormatIndicator, messageExpiryInterval, contentType, responseTopic, correlationData, userProperties
}; };
if (n.willMsg) {
this.options.will.properties = {};
setStrProp(n.willMsg, this.options.will.properties, "contentType");
if(n.willMsg.userProps && /^ *{/.test(n.willMsg.userProps)) {
try {
this.options.will.properties.userProperties = JSON.parse(n.willMsg.userProps)
} catch(err) {}
} }
n.willMsg.responseTopic = n.willMsg.respTopic;
setStrProp(n.willMsg, this.options.will.properties, "responseTopic");
n.willMsg.correlationData = n.willMsg.correl;
setBufferProp(n.willMsg, this.options.will.properties, "correlationData");
n.willMsg.willDelayInterval = n.willMsg.delay
setIntProp(n.willMsg,this.options.will.properties, "willDelayInterval")
n.willMsg.messageExpiryInterval = n.willMsg.expiry
setIntProp(n.willMsg,this.options.will.properties, "messageExpiryInterval")
this.options.will.payloadFormatIndicator = true;
}
}
// console.log(this.brokerurl,this.options);
// Define functions called by MQTT in and out nodes // Define functions called by MQTT in and out nodes
var node = this; var node = this;
@ -376,17 +420,18 @@ module.exports = function(RED) {
node.client.on('connect', function (connack) { node.client.on('connect', function (connack) {
node.connecting = false; node.connecting = false;
node.connected = true; node.connected = true;
node.topicAliases = {};
node.log(RED._("mqtt.state.connected",{broker:(node.clientid?node.clientid+"@":"")+node.brokerurl})); node.log(RED._("mqtt.state.connected",{broker:(node.clientid?node.clientid+"@":"")+node.brokerurl}));
if(node.options.protocolVersion == 5 && connack && connack.hasOwnProperty("properties")) { if(node.options.protocolVersion == 5 && connack && connack.hasOwnProperty("properties")) {
if(typeof connack.properties == "object") { if(typeof connack.properties == "object") {
//clean & assign all props sent from server. //clean & assign all props sent from server.
setIntProp(connack.properties, node.serverProperties, "topicAliasMaximum", 1); setIntProp(connack.properties, node.serverProperties, "topicAliasMaximum", 0);
setIntProp(connack.properties, node.serverProperties, "receiveMaximum", 0); setIntProp(connack.properties, node.serverProperties, "receiveMaximum", 0);
setIntProp(connack.properties, node.serverProperties, "sessionExpiryInterval", 0, 0xFFFFFFFF); setIntProp(connack.properties, node.serverProperties, "sessionExpiryInterval", 0, 0xFFFFFFFF);
setIntProp(connack.properties, node.serverProperties, "maximumQoS", 0, 2); setIntProp(connack.properties, node.serverProperties, "maximumQoS", 0, 2);
setBoolProp(connack.properties, node.serverProperties, "retainAvailable"); setBoolProp(connack.properties, node.serverProperties, "retainAvailable",true);
setBoolProp(connack.properties, node.serverProperties, "wildcardSubscriptionAvailable"); setBoolProp(connack.properties, node.serverProperties, "wildcardSubscriptionAvailable", true);
setBoolProp(connack.properties, node.serverProperties, "subscriptionIdentifiersAvailable"); setBoolProp(connack.properties, node.serverProperties, "subscriptionIdentifiersAvailable", true);
setBoolProp(connack.properties, node.serverProperties, "sharedSubscriptionAvailable"); setBoolProp(connack.properties, node.serverProperties, "sharedSubscriptionAvailable");
setIntProp(connack.properties, node.serverProperties, "maximumPacketSize", 0); setIntProp(connack.properties, node.serverProperties, "maximumPacketSize", 0);
setIntProp(connack.properties, node.serverProperties, "serverKeepAlive"); setIntProp(connack.properties, node.serverProperties, "serverKeepAlive");
@ -395,7 +440,7 @@ module.exports = function(RED) {
setStrProp(connack.properties, node.serverProperties, "assignedClientIdentifier"); setStrProp(connack.properties, node.serverProperties, "assignedClientIdentifier");
setStrProp(connack.properties, node.serverProperties, "reasonString"); setStrProp(connack.properties, node.serverProperties, "reasonString");
setUserProperties(connack.properties, node.serverProperties); setUserProperties(connack.properties, node.serverProperties);
debug("MQTTBrokerNode: ⬆ CONNECTED. node.serverProperties ==> ", node.serverProperties );//TODO: remove // node.debug("CONNECTED. node.serverProperties ==> "+JSON.stringify(node.serverProperties));//TODO: remove
} }
} }
for (var id in node.users) { for (var id in node.users) {
@ -416,12 +461,10 @@ module.exports = function(RED) {
if (node.subscriptions[s].hasOwnProperty(r)) { if (node.subscriptions[s].hasOwnProperty(r)) {
qos = Math.max(qos,node.subscriptions[s][r].qos); qos = Math.max(qos,node.subscriptions[s][r].qos);
_options = node.subscriptions[s][r].options; _options = node.subscriptions[s][r].options;
debug(`MQTTBrokerNode:${node.id}: Re-subscribe - registering handler ref ${r} for ${s} `);//TODO: remove
node.client.on('message',node.subscriptions[s][r].handler); node.client.on('message',node.subscriptions[s][r].handler);
} }
} }
_options.qos = _options.qos || qos; _options.qos = _options.qos || qos;
debug(`MQTTBrokerNode:${node.id}: Re-subscribe - subscribing to topic '${topic}'`, _options);//TODO: remove
node.client.subscribe(topic, _options); node.client.subscribe(topic, _options);
} }
} }
@ -432,7 +475,6 @@ module.exports = function(RED) {
} }
}); });
node.client.on("reconnect", function() { node.client.on("reconnect", function() {
debug('MQTTBrokerNode reconnect event'); //TODO: remove
for (var id in node.users) { for (var id in node.users) {
if (node.users.hasOwnProperty(id)) { if (node.users.hasOwnProperty(id)) {
node.users[id].status({fill:"yellow",shape:"ring",text:"node-red:common.status.connecting"}); node.users[id].status({fill:"yellow",shape:"ring",text:"node-red:common.status.connecting"});
@ -442,14 +484,12 @@ module.exports = function(RED) {
//TODO: what to do with this event? Anything? Necessary? //TODO: what to do with this event? Anything? Necessary?
node.client.on("disconnect", function(packet) { node.client.on("disconnect", function(packet) {
//Emitted after receiving disconnect packet from broker. MQTT 5.0 feature. //Emitted after receiving disconnect packet from broker. MQTT 5.0 feature.
debug('MQTTBrokerNode disconnect event', packet); //TODO: remove //TODO: remove
var rc = packet && packet.properties && packet.properties.reasonString; var rc = packet && packet.properties && packet.properties.reasonString;
var rc = packet && packet.properties && packet.reasonCode; var rc = packet && packet.properties && packet.reasonCode;
//TODO: If keeping this event, do we use these? log these? //TODO: If keeping this event, do we use these? log these?
}); });
// Register disconnect handlers // Register disconnect handlers
node.client.on('close', function () { node.client.on('close', function () {
debug('MQTTBrokerNode close event', arguments); //TODO: remove
if (node.connected) { if (node.connected) {
node.connected = false; node.connected = false;
node.log(RED._("mqtt.state.disconnected",{broker:(node.clientid?node.clientid+"@":"")+node.brokerurl})); node.log(RED._("mqtt.state.disconnected",{broker:(node.clientid?node.clientid+"@":"")+node.brokerurl}));
@ -466,7 +506,6 @@ module.exports = function(RED) {
// Register connect error handler // Register connect error handler
// The client's own reconnect logic will take care of errors // The client's own reconnect logic will take care of errors
node.client.on('error', function (error) { node.client.on('error', function (error) {
debug('MQTTBrokerNode error event', error); //TODO: remove
}); });
}catch(err) { }catch(err) {
console.log(err); console.log(err);
@ -474,6 +513,8 @@ module.exports = function(RED) {
} }
}; };
this.subscriptionIds = {};
this.subid = 1;
this.subscribe = function (topic,options,callback,ref) { this.subscribe = function (topic,options,callback,ref) {
ref = ref||0; ref = ref||0;
var qos; var qos;
@ -484,27 +525,33 @@ module.exports = function(RED) {
options = {}; options = {};
} }
options.qos = qos; options.qos = qos;
if (!node.subscriptionIds[topic]) {
node.subscriptionIds[topic] = node.subid++;
}
options.properties = options.properties || {};
options.properties.subscriptionIdentifier = node.subscriptionIds[topic];
node.subscriptions[topic] = node.subscriptions[topic]||{}; node.subscriptions[topic] = node.subscriptions[topic]||{};
var sub = { var sub = {
topic:topic, topic:topic,
qos:qos, qos:qos,
options:options, options:options,
handler:function(mtopic,mpayload, mpacket) { handler:function(mtopic,mpayload, mpacket) {
debug(`MQTTBrokerNode:${node.id}: this.subscribe.handler - attempting to match '${topic}' to '${mtopic}' `, mpacket); //TODO: remove
if(mpacket.properties && options.properties && mpacket.properties.subscriptionIdentifier && options.properties.subscriptionIdentifier && (mpacket.properties.subscriptionIdentifier !== options.properties.subscriptionIdentifier) ) { if(mpacket.properties && options.properties && mpacket.properties.subscriptionIdentifier && options.properties.subscriptionIdentifier && (mpacket.properties.subscriptionIdentifier !== options.properties.subscriptionIdentifier) ) {
//do nothing as subscriptionIdentifier does not match //do nothing as subscriptionIdentifier does not match
debug(`MQTTBrokerNode:${node.id}: > no match - this nodes subID (${options.properties.subscriptionIdentifier}) !== packet subID (${mpacket.properties.subscriptionIdentifier})`); //TODO: remove // node.debug(`> no match - this nodes subID (${options.properties.subscriptionIdentifier}) !== packet subID (${mpacket.properties.subscriptionIdentifier})`); //TODO: remove
} else if (matchTopic(topic,mtopic)) { } else if (matchTopic(topic,mtopic)) {
debug(`MQTTBrokerNode:${node.id}: > MATCHED '${topic}' to '${mtopic}' - performing callback`); //TODO: remove // node.debug(`> MATCHED '${topic}' to '${mtopic}' - performing callback`); //TODO: remove
callback(mtopic,mpayload, mpacket); callback(mtopic,mpayload, mpacket);
} else } else {
debug(`MQTTBrokerNode:${node.id}: > no match / no callback`); //TODO: remove // node.debug(`> no match / no callback`); //TODO: remove
}
}, },
ref: ref ref: ref
}; };
node.subscriptions[topic][ref] = sub; node.subscriptions[topic][ref] = sub;
if (node.connected) { if (node.connected) {
debug(`MQTTBrokerNode:${node.id}: this.subscribe - registering handler ref ${ref} for ${topic} and subscribing`, options); //TODO: remove // node.debug(`this.subscribe - registering handler ref ${ref} for ${topic} and subscribing `+JSON.stringify(options)); //TODO: remove
node.client.on('message',sub.handler); node.client.on('message',sub.handler);
node.client.subscribe(topic, options); node.client.subscribe(topic, options);
} }
@ -513,12 +560,12 @@ module.exports = function(RED) {
this.unsubscribe = function (topic, ref, removed) { this.unsubscribe = function (topic, ref, removed) {
ref = ref||0; ref = ref||0;
var sub = node.subscriptions[topic]; var sub = node.subscriptions[topic];
var _debug = `MQTTBrokerNode ${node.id}: unsubscribe for topic ${topic} called... ` ; //TODO: remove // var _debug = `unsubscribe for topic ${topic} called... ` ; //TODO: remove
if (sub) { if (sub) {
_debug += "sub found. " //TODO: remove // _debug += "sub found. " //TODO: remove
if (sub[ref]) { if (sub[ref]) {
// debug(`MQTTBrokerNode:${node.id}: this.unsubscribe - removing handler ref ${ref} for ${topic} `); //TODO: remove // debug(`this.unsubscribe - removing handler ref ${ref} for ${topic} `); //TODO: remove
_debug += `removing handler ref ${ref} for ${topic}. ` // _debug += `removing handler ref ${ref} for ${topic}. `
node.client.removeListener('message',sub[ref].handler); node.client.removeListener('message',sub[ref].handler);
delete sub[ref]; delete sub[ref];
} }
@ -528,18 +575,20 @@ module.exports = function(RED) {
if (Object.keys(sub).length === 0) { if (Object.keys(sub).length === 0) {
delete node.subscriptions[topic]; delete node.subscriptions[topic];
delete node.subscriptionIds[topic];
if (node.connected) { if (node.connected) {
_debug += `calling client.unsubscribe to remove topic ${topic}` //TODO: remove // _debug += `calling client.unsubscribe to remove topic ${topic}` //TODO: remove
node.client.unsubscribe(topic); node.client.unsubscribe(topic);
} }
} }
//} //}
} else { } else {
_debug += "sub not found! "; //TODO: remove // _debug += "sub not found! "; //TODO: remove
} }
debug(_debug); //TODO: remove // node.debug(_debug); //TODO: remove
}; };
this.topicAliases = {};
this.publish = function (msg,done) { this.publish = function (msg,done) {
if (node.connected) { if (node.connected) {
@ -563,16 +612,28 @@ module.exports = function(RED) {
setBufferProp(msg, options.properties, "correlationData"); setBufferProp(msg, options.properties, "correlationData");
setStrProp(msg, options.properties, "contentType"); setStrProp(msg, options.properties, "contentType");
setIntProp(msg, options.properties, "messageExpiryInterval", 0); setIntProp(msg, options.properties, "messageExpiryInterval", 0);
if (msg.userProperties) {
options.properties.userProperties = msg.userProperties;
}
setUserProperties(msg.userProperties, options.properties); setUserProperties(msg.userProperties, options.properties);
setIntProp(msg, options.properties, "topicAlias", 1, node.serverProperties.topicAliasMaximum || 0); setIntProp(msg, options.properties, "topicAlias", 1, node.serverProperties.topicAliasMaximum || 0);
setBoolProp(msg, options.properties, "payloadFormatIndicator"); setBoolProp(msg, options.properties, "payloadFormatIndicator");
//FUTURE setIntProp(msg, options.properties, "subscriptionIdentifier", 1, 268435455); //FUTURE setIntProp(msg, options.properties, "subscriptionIdentifier", 1, 268435455);
if (options.properties.topicAlias) {
if (!node.topicAliases.hasOwnProperty(options.properties.topicAlias) && msg.topic == "") {
done("Invalid topicAlias");
return
} }
// debug(`MQTTBrokerNode:${node.id}: publish - sending payload to ${msg.topic ? msg.topic : (msg.topicAlias ? 'topicAlias-'+msg.topicAlias : '???') } `, options);//TODO: remove if (node.topicAliases[options.properties.topicAlias] === msg.topic) {
debug(`MQTTBrokerNode:${node.id}: publish - sending payload to ${msg.topic} `, options);//TODO: remove msg.topic = ""
} else {
node.topicAliases[options.properties.topicAlias] = msg.topic
}
}
}
node.client.publish(msg.topic, msg.payload, options, function(err) { node.client.publish(msg.topic, msg.payload, options, function(err) {
if(err) node.error(err,msg);//catch errors done && done(err);
done && done();
return return
}); });
} }
@ -611,8 +672,6 @@ module.exports = function(RED) {
this.topic = n.topic; this.topic = n.topic;
this.qos = parseInt(n.qos); this.qos = parseInt(n.qos);
this.subscriptionIdentifier = n.subscriptionIdentifier;//https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901117 this.subscriptionIdentifier = n.subscriptionIdentifier;//https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901117
this.userProperties = n.userProperties;//https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901116
this.userPropertiesType = n.userPropertiesType;
this.nl = n.nl; this.nl = n.nl;
this.rap = n.rap; this.rap = n.rap;
this.rh = n.rh; this.rh = n.rh;
@ -635,12 +694,12 @@ module.exports = function(RED) {
node.brokerConn.register(this); node.brokerConn.register(this);
let options = { qos: this.qos }; let options = { qos: this.qos };
if(v5) { if(v5) {
options.properties = {}; // options.properties = {};
if(node.userProperties) { // if(node.userProperties) {
let userProperties = RED.util.evaluateNodeProperty(node.userProperties, node.userPropertiesType, node, {}); // let userProperties = RED.util.evaluateNodeProperty(node.userProperties, node.userPropertiesType, node, {});
setUserProperties(userProperties, options.properties); // setUserProperties(userProperties, options.properties);
} // }
setIntProp(node,options.properties,"subscriptionIdentifier", 1); // setIntProp(node,options.properties,"subscriptionIdentifier", 1);
setIntProp(node, options, "rh"); setIntProp(node, options, "rh");
if(node.nl === "true" || node.nl === true) options.nl = true; if(node.nl === "true" || node.nl === true) options.nl = true;
else if(node.nl === "false" || node.nl === false) options.nl = false; else if(node.nl === "false" || node.nl === false) options.nl = false;
@ -649,7 +708,7 @@ module.exports = function(RED) {
} }
this.brokerConn.subscribe(this.topic,options,function(topic,payload,packet) { this.brokerConn.subscribe(this.topic,options,function(topic,payload,packet) {
debug(`MQTTInNode:${node.id}: Broker sent ${topic}, datatype ${node.datatype}`, packet);//TODO: remove // node.debug(`Sent ${topic}, datatype ${node.datatype} `+JSON.stringify(packet));//TODO: remove
if (node.datatype === "buffer") { if (node.datatype === "buffer") {
// payload = payload; // payload = payload;
} else if (node.datatype === "base64") { } else if (node.datatype === "base64") {
@ -709,16 +768,15 @@ module.exports = function(RED) {
this.qos = n.qos || null; this.qos = n.qos || null;
this.retain = n.retain; this.retain = n.retain;
this.broker = n.broker; this.broker = n.broker;
this.responseTopic = n.responseTopic;//https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901114 this.responseTopic = n.respTopic;//https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901114
this.responseTopicType = n.responseTopicType; this.correlationData = n.correl;//https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901115
this.correlationData = n.correlationData;//https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901115
this.correlationDataType = n.correlationDataType;
this.contentType = n.contentType;//https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901118 this.contentType = n.contentType;//https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901118
this.contentTypeType = n.contentTypeType; this.messageExpiryInterval = n.expiry; //https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901112
this.messageExpiryInterval = n.messageExpiryInterval; //https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901112 try {
this.messageExpiryIntervalType = n.messageExpiryIntervalType; if (/^ *{/.test(n.userProps)) {
this.userProperties = n.userProperties;//https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901116 this.userProperties = JSON.parse(n.userProps);//https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901116
this.userPropertiesType = n.userPropertiesType; }
} catch(err) {}
// this.topicAlias = n.topicAlias; //https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901113 // this.topicAlias = n.topicAlias; //https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901113
// this.payloadFormatIndicator = n.payloadFormatIndicator; //https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901111 // this.payloadFormatIndicator = n.payloadFormatIndicator; //https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901111
// this.subscriptionIdentifier = n.subscriptionIdentifier;//https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901117 // this.subscriptionIdentifier = n.subscriptionIdentifier;//https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901117
@ -744,25 +802,20 @@ module.exports = function(RED) {
let msgPropOverride = function(propName) { if(node[propName]) { msg[propName] = node[propName]; } } let msgPropOverride = function(propName) { if(node[propName]) { msg[propName] = node[propName]; } }
msgPropOverride("topic"); msgPropOverride("topic");
if(v5) { if(v5) {
if(node.userProperties && node.userPropertiesType !== "none") { if(node.userProperties) {
let userProperties = RED.util.evaluateNodeProperty(node.userProperties, node.userPropertiesType, node, msg); msg.userProperties = node.userProperties;
if(userProperties) msg.userProperties = userProperties;
} }
if(node.responseTopic && node.responseTopicType !== "none") { if(node.responseTopic) {
let responseTopic = RED.util.evaluateNodeProperty(node.responseTopic, node.responseTopicType, node, msg); msg.responseTopic = node.responseTopic;
if(responseTopic) msg.responseTopic = responseTopic;
} }
if(node.correlationData && node.correlationDataType !== "none") { if(node.correlationData) {
let correlationData = RED.util.evaluateNodeProperty(node.correlationData, node.correlationDataType, node, msg); msg.correlationData = node.correlationData;
if(correlationData) msg.correlationData = correlationData;
} }
if(node.contentType && node.contentTypeType !== "none") { if(node.contentType) {
let contentType = RED.util.evaluateNodeProperty(node.contentType, node.contentTypeType, node, msg); msg.contentType = node.contentType;
if(contentType) msg.contentType = contentType;
} }
if(node.messageExpiryInterval && node.messageExpiryIntervalType !== "none") { if(node.messageExpiryInterval) {
let messageExpiryInterval = RED.util.evaluateNodeProperty(node.messageExpiryInterval, node.messageExpiryIntervalType, node, msg); msg.messageExpiryInterval = node.messageExpiryInterval;
if(messageExpiryInterval) msg.messageExpiryInterval = messageExpiryInterval;
} }
//Next, update/override the msg.xxxx properties from node config //Next, update/override the msg.xxxx properties from node config
//TODO: Should we be expecting msg.properties.xxxx instead of msg.xxxx? //TODO: Should we be expecting msg.properties.xxxx instead of msg.xxxx?
@ -774,11 +827,18 @@ module.exports = function(RED) {
//FUTURE setBoolProp(node,msg,"payloadFormatIndicator"); //FUTURE setBoolProp(node,msg,"payloadFormatIndicator");
//FUTURE setIntProp(node,msg,"subscriptionIdentifier"); //FUTURE setIntProp(node,msg,"subscriptionIdentifier");
} }
if (msg.userProperties && typeof msg.userProperties !== "object") {
delete msg.userProperties;
}
if (msg.hasOwnProperty("topicAlias") && !isNaN(msg.topicAlias) && (msg.topicAlias === 0 || node.brokerConn.serverProperties.topicAliasMaximum === 0 || msg.topicAlias > node.brokerConn.serverProperties.topicAliasMaximum)) {
delete msg.topicAlias;
}
if ( msg.hasOwnProperty("payload")) { if ( msg.hasOwnProperty("payload")) {
let topicOK = msg.hasOwnProperty("topic") && (typeof msg.topic === "string") && (msg.topic !== ""); let topicOK = msg.hasOwnProperty("topic") && (typeof msg.topic === "string") && (msg.topic !== "");
if (!topicOK && v5) { if (!topicOK && v5) {
//NOTE: A value of 0 (in server props topicAliasMaximum) indicates that the Server does not accept any Topic Aliases on this connection //NOTE: A value of 0 (in server props topicAliasMaximum) indicates that the Server does not accept any Topic Aliases on this connection
if (msg.hasOwnProperty("topicAlias") && typeof msg.topicAlias === "number" && msg.topicAlias >= 0 && node.brokerConn.serverProperties.topicAliasMaximum && node.brokerConn.serverProperties.topicAliasMaximum >= msg.topicAlias) { if (msg.hasOwnProperty("topicAlias") && !isNaN(msg.topicAlias) && msg.topicAlias >= 0 && node.brokerConn.serverProperties.topicAliasMaximum && node.brokerConn.serverProperties.topicAliasMaximum >= msg.topicAlias) {
topicOK = true; topicOK = true;
msg.topic = ""; //must be empty string msg.topic = ""; //must be empty string
} else if (msg.hasOwnProperty("responseTopic") && (typeof msg.responseTopic === "string") && (msg.responseTopic !== "")) { } else if (msg.hasOwnProperty("responseTopic") && (typeof msg.responseTopic === "string") && (msg.responseTopic !== "")) {
@ -789,11 +849,11 @@ module.exports = function(RED) {
} }
} }
if (topicOK) { // topic must exist if (topicOK) { // topic must exist
debug(`MQTTOutNode:${node.id}: sending msg to ${msg.topic}`, msg);//TODO: remove // node.debug(`sending msg to ${msg.topic} `+JSON.stringify(msg));//TODO: remove
this.brokerConn.publish(msg, function(){ this.brokerConn.publish(msg, function(err) {
let args = arguments; let args = arguments;
let l = args.length; let l = args.length;
done(); done(err);
}); // send the message }); // send the message
} else { } else {
node.warn(RED._("mqtt.errors.invalid-topic")); node.warn(RED._("mqtt.errors.invalid-topic"));

View File

@ -350,8 +350,9 @@
"retain": "Retain", "retain": "Retain",
"clientid": "Client ID", "clientid": "Client ID",
"port": "Port", "port": "Port",
"keepalive": "Keepalive time(s)", "keepalive": "Keep Alive",
"cleansession": "Use clean session", "cleansession": "Use clean session",
"cleanstart": "Use clean start",
"use-tls": "Enable secure (SSL/TLS) connection", "use-tls": "Enable secure (SSL/TLS) connection",
"tls-config":"TLS Configuration", "tls-config":"TLS Configuration",
"verify-server-cert":"Verify server certificate", "verify-server-cert":"Verify server certificate",
@ -361,23 +362,23 @@
"flags": "Flags", "flags": "Flags",
"nl": "Do not receive messages published by this client", "nl": "Do not receive messages published by this client",
"rap": "Keep retain flag of original publish", "rap": "Keep retain flag of original publish",
"rh": "Retain Handling", "rh": "Retained message handling ",
"rh0": "0, Always send retained messages", "rh0": "Send retained messages",
"rh1": "1, Send retained messages for new subscription", "rh1": "Only send for new subscriptions",
"rh2": "2, Never send retained messages", "rh2": "Do not send",
"responseTopic": "Response topic", "responseTopic": "Response topic",
"contentType": "Content Type", "contentType": "Content Type",
"correlationData": "Correlation Data", "correlationData": "Correlation Data",
"messageExpiryInterval": "Expiry (secs)", "expiry": "Expiry (secs)",
"sessionExpiry": "Session Expiry (secs)",
"topicAlias": "Alias", "topicAlias": "Alias",
"payloadFormatIndicator": "Format", "payloadFormatIndicator": "Format",
"payloadFormatIndicatorFalse": "unspecified bytes (Default)", "payloadFormatIndicatorFalse": "unspecified bytes (Default)",
"payloadFormatIndicatorTrue": "UTF-8 encoded payload", "payloadFormatIndicatorTrue": "UTF-8 encoded payload",
"protocolVersion": "Protocol Version", "protocolVersion": "Protocol",
"protocolVersion3": "MQTT V3.1 (legacy)", "protocolVersion3": "MQTT V3.1 (legacy)",
"protocolVersion4": "MQTT V3.1.1", "protocolVersion4": "MQTT V3.1.1",
"protocolVersion5": "MQTT V5", "protocolVersion5": "MQTT V5",
"sessionExpiryInterval": "Expiry(s)",
"topicAliasMaximum": "Alias Max", "topicAliasMaximum": "Alias Max",
"maximumPacketSize": "Max Packet Size", "maximumPacketSize": "Max Packet Size",
"receiveMaximum": "Receive Max" "receiveMaximum": "Receive Max"

View File

@ -23,6 +23,17 @@
<dd>0, fire and forget - 1, at least once - 2, once and once only.</dd> <dd>0, fire and forget - 1, at least once - 2, once and once only.</dd>
<dt>retain <span class="property-type">boolean</span></dt> <dt>retain <span class="property-type">boolean</span></dt>
<dd>true indicates the message was retained and may be old.</dd> <dd>true indicates the message was retained and may be old.</dd>
<dt class="optional">responseTopic <span class="property-type">string</span></dt>
<dd><b>MQTTv5</b>: the MQTT response topic for the message</dd>
<dt class="optional">correlationData <span class="property-type">Buffer</span></dt>
<dd><b>MQTTv5</b>: the correlation data for the message</dd>
<dt class="optional">contentType <span class="property-type">string</span></dt>
<dd><b>MQTTv5</b>: the content-type of the payload</dd>
<dt class="optional">userProperties <span class="property-type">object</span></dt>
<dd><b>MQTTv5</b>: any user properties of the message</dd>
<dt class="optional">messageExpiryInterval <span class="property-type">number</span></dt>
<dd><b>MQTTv5</b>: the expiry time, in seconds, of the message</dd>
</dl> </dl>
<h3>Details</h3> <h3>Details</h3>
The subscription topic can include MQTT wildcards, + for one level, # for multiple levels.</p> The subscription topic can include MQTT wildcards, + for one level, # for multiple levels.</p>
@ -37,15 +48,24 @@
<dl class="message-properties"> <dl class="message-properties">
<dt>payload <span class="property-type">string | buffer</span></dt> <dt>payload <span class="property-type">string | buffer</span></dt>
<dd> the payload to publish. If this property is not set, no message will be sent. To send a blank message, set this property to an empty String.</dd> <dd> the payload to publish. If this property is not set, no message will be sent. To send a blank message, set this property to an empty String.</dd>
<dt class="optional">topic <span class="property-type">string</span></dt> <dt class="optional">topic <span class="property-type">string</span></dt>
<dd> the MQTT topic to publish to.</dd> <dd> the MQTT topic to publish to.</dd>
<dt class="optional">qos <span class="property-type">number</span></dt> <dt class="optional">qos <span class="property-type">number</span></dt>
<dd>0, fire and forget - 1, at least once - 2, once and once only. Default 0.</dd> <dd>0, fire and forget - 1, at least once - 2, once and once only. Default 0.</dd>
<dt class="optional">retain <span class="property-type">boolean</span></dt> <dt class="optional">retain <span class="property-type">boolean</span></dt>
<dd>set to true to retain the message on the broker. Default false.</dd> <dd>set to true to retain the message on the broker. Default false.</dd>
<dt class="optional">responseTopic <span class="property-type">string</span></dt>
<dd><b>MQTTv5</b>: the MQTT response topic for the message</dd>
<dt class="optional">correlationData <span class="property-type">Buffer</span></dt>
<dd><b>MQTTv5</b>: the correlation data for the message</dd>
<dt class="optional">contentType <span class="property-type">string</span></dt>
<dd><b>MQTTv5</b>: the content-type of the payload</dd>
<dt class="optional">userProperties <span class="property-type">object</span></dt>
<dd><b>MQTTv5</b>: any user properties of the message</dd>
<dt class="optional">messageExpiryInterval <span class="property-type">number</span></dt>
<dd><b>MQTTv5</b>: the expiry time, in seconds, of the message</dd>
<dt class="optional">topicAlias <span class="property-type">number</span></dt>
<dd><b>MQTTv5</b>: the MQTT topic alias to use</dd>
</dl> </dl>
<h3>Details</h3> <h3>Details</h3>
<code>msg.payload</code> is used as the payload of the published message. <code>msg.payload</code> is used as the payload of the published message.