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

Update mqtt node options to include will/cleansession/keepalive

This commit is contained in:
Nick O'Leary 2015-09-01 22:30:15 +01:00
parent 437b2d506b
commit fa5e37993e
3 changed files with 198 additions and 95 deletions

View File

@ -30,8 +30,6 @@
<p>MQTT input node. Connects to a broker and subscribes to the specified topic. The topic may contain MQTT wildcards.</p>
<p>Outputs an object called <b>msg</b> containing <b>msg.topic, msg.payload, msg.qos</b> and <b>msg.retain</b>.</p>
<p><b>msg.payload</b> is usually a string, but can also be a binary buffer.</p>
<p>If a secure connection is being used, certificate checking can be disabled to allow connections to brokers using a self signed or non-trusted CA certificate.</p>
<p>Compatibility mode allows connections to brokers which do not support the MQTT V3.1.1 standard.</p>
</script>
<script type="text/javascript">
@ -89,9 +87,6 @@
<p>Connects to a MQTT broker and publishes <b>msg.payload</b> either to the <b>msg.topic</b> or to the topic specified in the edit window. The value in the edit window has precedence.</p>
<p>Likewise QoS and/or retain values in the edit panel will overwrite any <b>msg.qos</b> and <b>msg.retain</b> properties. If nothing is set they default to <i>0</i> and <i>false</i> respectively.</p>
<p>If <b>msg.payload</b> contains an object it will be stringified before being sent.</p>
<p>If a secure connection is being used, certificate checking can be disabled to allow connections to brokers using a self signed or non-trusted CA certificate.</p>
<p>Compatibility mode allows connections to brokers which do not support the MQTT V3.1.1 standard.</p>
</script>
<script type="text/javascript">
@ -119,6 +114,11 @@
</script>
<script type="text/x-red" data-template-name="mqtt-broker">
<div class="form-row">
<ul style="background: #fff; min-width: 550px; margin-bottom: 20px;" id="node-config-mqtt-broker-tabs"></ul>
</div>
<div id="node-config-mqtt-broker-tabs-content" style="min-height: 170px;">
<div id="mqtt-broker-tab-connection" style="display:none">
<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>
<input class="input-append-left" type="text" id="node-config-input-broker" placeholder="localhost" style="width: 40%;" >
@ -126,24 +126,22 @@
<input type="text" id="node-config-input-port" data-i18n="[placeholder]mqtt.label.port" style="width:45px">
</div>
<div class="form-row">
<label>&nbsp;</label>
<input type="checkbox" id="node-config-input-secureconn" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-config-input-secureconn" style="width: 70%;">Enable secure (SSL/TLS) connection</label>
<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" id="row-disablecertauth">
<label>&nbsp;</label>
<input type="checkbox" id="node-config-input-disablecertauth" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-config-input-disablecertauth" style="width: 70%;">Disable certificate authentication (secure connections only)</label>
<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">
<input type="checkbox" id="node-config-input-cleansession" style="margin-left: 30px; height: 1em;display: inline-block; width: auto; vertical-align: middle;">
<label for="node-config-input-cleansession" style="width: auto;" data-i18n="mqtt.label.cleansession"></label>
</div>
<div class="form-row">
<label>&nbsp;</label>
<input type="checkbox" id="node-config-input-compatmode" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-config-input-compatmode" style="width: 70%;">Compatibility for brokers not supporting MQTT v3.1.1</label>
<label for="node-config-input-compatmode" style="width: auto;" data-i18n="mqtt.label.compatmode"></label>
</div>
<div class="form-row">
<label for="node-config-input-clientid"><i class="fa fa-tag"></i> Client ID</label>
<input type="text" id="node-config-input-clientid" placeholder="Leave blank for auto generated">
</div>
<div id="mqtt-broker-tab-security" style="display:none">
<div class="form-row">
<label for="node-config-input-user"><i class="fa fa-user"></i> <span data-i18n="common.label.username"></span></label>
<input type="text" id="node-config-input-user">
@ -152,6 +150,41 @@
<label for="node-config-input-password"><i class="fa fa-lock"></i> <span data-i18n="common.label.password"></span></label>
<input type="password" id="node-config-input-password">
</div>
<div class="form-row">
<input type="checkbox" id="node-config-input-usetls" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-config-input-usetls" style="width: 70%;" data-i18n="mqtt.label.use-tls"></label>
</div>
<div class="form-row">
<input type="checkbox" id="node-config-input-verifyservercert" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-config-input-verifyservercert" style="width: 70%;" data-i18n="mqtt.label.verify-server-cert"></label>
</div>
</div>
<div id="mqtt-broker-tab-will" style="display:none">
<div class="form-row">
<label for="node-config-input-willTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
<input type="text" id="node-config-input-willTopic" data-i18n="[placeholder]mqtt.placeholder.will-topic">
</div>
<div class="form-row">
<label for="node-config-input-willQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
<select id="node-config-input-willQos" style="width:125px !important">
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
&nbsp;&nbsp;<i class="fa fa-history"></i>&nbsp;<span data-i18n="mqtt.retain"></span> &nbsp;<select id="node-config-input-willRetain" style="width:125px !important">
<option value="false" data-i18n="mqtt.false"></option>
<option value="true" data-i18n="mqtt.true"></option>
</select>
</div>
<div class="form-row">
<label for="node-config-input-willPayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
<input type="text" id="node-config-input-willPayload" data-i18n="[placeholder]common.label.payload">
</div>
</div>
</div>
</script>
<script type="text/javascript">
@ -160,11 +193,23 @@
defaults: {
broker: {value:"",required:true},
port: {value:1883,required:true,validate:RED.validators.number()},
clientid: { value:"" },
secureconn: {value: false},
disablecertauth: { value: false},
clientid: { value:"", validate: function(v) {
if ($("#node-config-input-clientid").length) {
// Currently editing the node
return $("#node-config-input-cleansession").is(":checked") || v.length > 0;
} else {
return this.cleansession || v.length > 0;
}
}},
usetls: {value: false},
verifyservercert: { value: false},
compatmode: { value: true},
mqttkeepalive: {value:15}
keepalive: {value:15,validate:RED.validators.number()},
cleansession: {value: true},
willTopic: {value:""},
willQos: {value:0},
willRetain: {value:false},
willPayload: {value:""}
},
credentials: {
user: {type:"text"},
@ -175,32 +220,67 @@
return (this.clientid?this.clientid+"@":"")+this.broker+":"+this.port;
},
oneditprepare: function () {
if (this.broker && typeof this.secureconn === 'undefined'){
this.secureconn = false;
var tabs = RED.tabs.create({
id: "node-config-mqtt-broker-tabs",
onchange: function(tab) {
$("#node-config-mqtt-broker-tabs-content").children().hide();
$("#" + tab.id).show();
}
if (this.broker && typeof this.disablecertauth === 'undefined'){
this.disablecertauth = false;
});
tabs.addTab({
id: "mqtt-broker-tab-connection",
label: this._("mqtt.tabs-label.connection")
});
tabs.addTab({
id: "mqtt-broker-tab-security",
label: this._("mqtt.tabs-label.security")
});
tabs.addTab({
id: "mqtt-broker-tab-will",
label: this._("mqtt.tabs-label.will")
});
setTimeout(function() { tabs.resize()},0);
if (typeof this.usetls === 'undefined'){
this.usetls = false;
$("#node-config-input-usetls").prop("checked",false);
}
if (this.broker && typeof this.compatmode === 'undefined'){
if (typeof this.verifyservercert === 'undefined'){
this.verifyservercert = true;
$("#node-config-input-verifyservercert").prop("checked",true);
}
if (typeof this.compatmode === 'undefined'){
this.compatmode = true;
$("#node-config-input-compatmode").prop('checked', true);
}
if (this.broker && typeof this.mqttkeepalive === 'undefined'){
this.mqttkeepalive = 15;
if (typeof this.keepalive === 'undefined'){
this.keepalive = 15;
}
if (this.secureconn == true) {
$("#row-disablecertauth").show();
function updateTLSOptions() {
if ($("#node-config-input-usetls").is(':checked')) {
$("#node-config-input-verifyservercert").prop("disabled", false);
$("#node-config-input-verifyservercert").next().css("color","");
} else {
$("#row-disablecertauth").hide();
$("#node-config-input-verifyservercert").prop("disabled", true);
$("#node-config-input-verifyservercert").next().css("color","#aaa");
}
$("#node-config-input-secureconn").on("click",function() {
if($(this).is(':checked')) {
$("#row-disablecertauth").show();
}
updateTLSOptions();
$("#node-config-input-usetls").on("click",function() {
updateTLSOptions();
});
var node = this;
function updateClientId() {
if ($("#node-config-input-cleansession").is(":checked")) {
$("#node-config-input-clientid").attr("placeholder",node._("mqtt.placeholder.clientid"));
} else {
$("#row-disablecertauth").hide();
$("#node-config-input-clientid").attr("placeholder",node._("mqtt.placeholder.clientid-nonclean"));
}
$("#node-config-input-clientid").change();
}
setTimeout(updateClientId,0);
$("#node-config-input-cleansession").on("click",function() {
updateClientId();
});
}
});

View File

@ -36,17 +36,17 @@ module.exports = function(RED) {
this.broker = n.broker;
this.port = n.port;
this.clientid = n.clientid;
this.secureconn = n.secureconn;
this.disablecertauth = n.disablecertauth;
this.usetls = n.usetls;
this.verifyservercert = n.verifyservercert;
this.compatmode = n.compatmode;
this.mqttkeepalive = n.mqttkeepalive;
this.keepalive = n.keepalive;
this.cleansession = n.cleansession;
// Config node state
this.brokerurl = "";
this.connected = false;
this.connecting = false;
this.usecount = 0;
this.logdisconnect = true;
this.options = {};
this.queue = [];
this.subscriptions = {};
@ -61,22 +61,27 @@ module.exports = function(RED) {
// If the config node is missing certain options (it was probably deployed prior to an update to the node code),
// select/generate sensible options for the new fields
if (typeof this.secureconn === 'undefined'){
this.secureconn = false;
if (typeof this.usetls === 'undefined'){
this.usetls = false;
}
if (typeof this.compatmode === 'undefined'){
this.compatmode = true;
}
if (typeof this.disablecertauth === 'undefined'){
this.disablecertauth = false;
if (typeof this.verifyservercert === 'undefined'){
this.verifyservercert = false;
}
if (typeof this.mqttkeepalive === 'undefined'){
this.mqttkeepalive = 15;
if (typeof this.keepalive === 'undefined'){
this.keepalive = 15;
} else if (typeof this.keepalive === 'string') {
this.keepalive = Number(this.keepalive);
}
if (typeof this.cleansession === 'undefined') {
this.cleansession = true;
}
// Create the URL to pass in to the MQTT.js library
if (this.brokerurl == "") {
if (this.secureconn) {
if (this.usetls) {
this.brokerurl="mqtts://";
} else {
this.brokerurl="mqtt://";
@ -88,22 +93,32 @@ module.exports = function(RED) {
}
}
if (!this.cleansession && !this.clientid) {
this.cleansession = true;
this.warn(RED._("mqtt.errors.nonclean-missingclientid"));
}
// Build options for passing to the MQTT.js API
this.options.clientId = this.clientid || 'mqtt_' + (1+Math.random()*4294967295).toString(16);
this.options.username = this.username;
this.options.password = this.password;
this.options.keepalive = this.mqttkeepalive;
this.options.reconnectPeriod = 5000;
this.options.keepalive = this.keepalive;
this.options.clean = this.clean;
this.options.reconnectPeriod = RED.settings.mqttReconnectTime||5000;
if (this.compatmode == "true" || this.compatmode === true){
this.log('Using compatibility mode for non-MQTT v3.1.1 brokers');
this.options.protocolId = 'MQIsdp';
this.options.protocolVersion = 3;
}
if (this.disablecertauth == "true" || this.disablecertauth === true) {
this.log(' Warning: Certificate checking is disabled for this connection');
this.options.rejectUnauthorized = false;
} else {
this.options.rejectUnauthorized = true;
this.options.rejectUnauthorized = (this.verifyservercert == "true" || this.verifyservercert === true)
if (n.willTopic) {
this.options.will = {
topic: n.willTopic,
payload: n.willPayload || "",
qos: Number(n.willQos||0),
retain: n.willRetain=="true"|| n.willRetain===true
};
}
// Define functions called by MQTT in and out nodes
@ -123,12 +138,10 @@ module.exports = function(RED) {
if (!node.connected && !node.connecting) {
node.connecting = true;
node.client = mqtt.connect(node.brokerurl ,node.options);
// Register successful connect or reconnect handler
node.client.on('connect', function () {
node.connected = true;
node.logdisconnect = true;
node.log("Connected to broker: "+(node.clientid?node.clientid+"@":"")+node.brokerurl);
node.log(RED._("mqtt.state.connected",{broker:(node.clientid?node.clientid+"@":"")+node.brokerurl}));
node.emit('connected');
// Remove any existing listeners before resubscribing to avoid duplicates in the event of a re-connection
@ -156,26 +169,18 @@ module.exports = function(RED) {
// Register disconnect handlers
node.client.on('close', function () {
if (node.connected && node.logdisconnect ) {
if (node.connected) {
node.connected = false;
node.logdisconnect = false;
node.log("Disconnected from broker: "+(node.clientid?node.clientid+"@":"")+node.brokerurl);
node.emit('disconnected');
}
});
node.client.on('offline', function () {
if (node.connected && node.logdisconnect ) {
node.connected = false;
node.logdisconnect = false;
node.log("Disconnected from broker: "+(node.clientid?node.clientid+"@":"")+node.brokerurl);
node.log(RED._("mqtt.state.disconnected",{broker:(node.clientid?node.clientid+"@":"")+node.brokerurl}));
node.emit('disconnected');
} else if (node.connecting) {
node.log(RED._("mqtt.state.connect-failed",{broker:(node.clientid?node.clientid+"@":"")+node.brokerurl}));
}
});
// Register connect error handler
node.client.on('error', function (error) {
node.log("" + error);
console.log("ERROR",error);
if (node.connecting) {
node.client.end();
node.connecting = false;

View File

@ -211,13 +211,30 @@
},
"mqtt": {
"label": {
"broker": "Broker",
"broker": "Server",
"qos": "QoS",
"clientid": "Client ID",
"port": "Port"
"port": "Port",
"keepalive": "Keep alive time (s)",
"cleansession": "Use clean session",
"use-tls": "Enable secure (SSL/TLS) connection",
"verify-server-cert":"Verify server certificate",
"compatmode": "Use legacy MQTT 3.1 support"
},
"tabs-label": {
"connection": "Connection",
"security": "Security",
"will": "Will Message"
},
"placeholder": {
"clientid": "Leave blank for auto generated"
"clientid": "Leave blank for auto generated",
"clientid-nonclean":"Must be set for non-clean sessions",
"will-topic": "Leave blank to disable will message"
},
"state": {
"connected": "Connected to broker: __broker__",
"disconnected": "Disconnected from broker: __broker__",
"connect-failed": "Connection failed to broker: __broker__"
},
"retain": "Retain",
"true": "true",
@ -226,7 +243,8 @@
"errors": {
"not-defined": "topic not defined",
"missing-config": "missing broker configuration",
"invalid-topic": "Invalid topic specified"
"invalid-topic": "Invalid topic specified",
"nonclean-missingclientid": "No client ID set, using clean session"
}
},
"httpin": {