node-red-contrib-mqtt-gem
Version:
MQTT nodes with environment variables support for dynamic enable and parameters
920 lines (882 loc) • 55.9 kB
HTML
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<style>
.mqtt-form-row-cols2>input.mqtt-form-row-col1 {
width: calc(35% - 75px);
}
.mqtt-form-row-cols2>select.mqtt-form-row-col1 {
width: calc(35% - 75px);
}
.mqtt-form-row-cols2>label.mqtt-form-row-col2 {
width: 100px;
margin-left: 42px;
display: inline-block;
}
.mqtt-form-row-cols2>input.mqtt-form-row-col2 {
width: calc(35% - 75px);
display: inline-block;
}
.mqtt-form-row-cols2>select.mqtt-form-row-col2 {
width: calc(35% - 75px);
display: inline-block;
}
.form-row.mqtt5-out>label {
width: 130px;
}
.form-row.mqtt-flags-row>label {
vertical-align: top;
}
.form-row.mqtt-flags-row>.mqtt-flags {
display: inline-block;
width: 70%
}
.form-row.mqtt-flags-row>.mqtt-flags>.mqtt-flag>label {
display: block;
width: 100%;
}
.form-row.mqtt-flags-row>.mqtt-flags>.mqtt-flag>label>input {
position: relative;
vertical-align: bottom;
top: -2px;
width: 15px;
height: 15px;
}
.form-row-mqtt5 {
display: none;
}
.form-row-mqtt5.form-row-mqtt5-active:not(.form-row-mqtt-static-disabled) {
display: block
}
.form-row-mqtt-static-disabled {
display: none;
/* opacity: 0.3;
pointer-events: none; */
}
.form-row.form-row-mqtt-datatype-tip>.form-tips {
width: calc(70% - 18px);
display: inline-block;
margin-top: -8px;
}
</style>
<script type="text/html" data-template-name="mqtt-gem in">
<div class="form-row">
<label for="node-input-broker"><i class="fa fa-globe"></i> <span data-i18n="mqtt.label.broker"></span></label>
<input type="text" id="node-input-broker">
</div>
<div class="form-row">
<label for="node-input-topicType" data-i18n="mqtt.label.action"></label>
<select id="node-input-topicType" style="width: 70%">
<option value="topic" data-i18n="mqtt.label.staticTopic"></option>
<option value="dynamic" data-i18n="mqtt.label.dynamicTopic"></option>
</select>
<input type="hidden" id="node-input-inputs">
</div>
<div class="form-row form-row-mqtt-static">
<label for="node-input-topic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
<input type="text" id="node-input-topic" data-i18n="[placeholder]common.label.topic">
</div>
<div class="form-row form-row-mqtt-static">
<label for="node-input-qos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
<select id="node-input-qos" style="width:125px !important">
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
</div>
<div class="form-row mqtt-flags-row form-row-mqtt5 form-row-mqtt-static">
<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-flag">
<label for="node-input-nl">
<input type="checkbox" id="node-input-nl">
<span data-i18n="mqtt.label.nl"></span>
</label>
</div>
<div class="mqtt-flag">
<label for="node-input-rap">
<input type="checkbox" id="node-input-rap">
<span data-i18n="mqtt.label.rap"></span>
</label>
</div>
</div>
</div>
<div class="form-row form-row-mqtt5 form-row-mqtt-static">
<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="margin-left: 104px; width: 70%">
<option value="0" data-i18n="mqtt.label.rh0"></option>
<option value="1" data-i18n="mqtt.label.rh1"></option>
<option value="2" data-i18n="mqtt.label.rh2"></option>
</select>
</div>
<div class="form-row">
<label for="node-input-datatype"><i class="fa fa-sign-out"></i> <span data-i18n="mqtt.label.output"></span></label>
<select id="node-input-datatype" style="width:70%;">
<option value="auto-detect" data-i18n="mqtt.output.auto-detect"></option>
<option value="auto" data-i18n="mqtt.output.auto"></option>
<option value="buffer" data-i18n="mqtt.output.buffer"></option>
<option value="utf8" data-i18n="mqtt.output.string"></option>
<option value="json" data-i18n="mqtt.output.json"></option>
<option value="base64" data-i18n="mqtt.output.base64"></option>
</select>
</div>
<div class="form-row form-row-mqtt-datatype-tip">
<label> </label>
<div class="form-tips" id="mqtt-in-datatype-depreciated-tip"><span data-i18n="mqtt.label.auto-mode-depreciated"></span></div>
</div>
<div class="form-row">
<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">
</div>
</script>
<script type="text/html" data-template-name="mqtt-gem out">
<div class="form-row">
<label for="node-input-broker"><i class="fa fa-globe"></i> <span data-i18n="mqtt.label.broker"></span></label>
<input type="text" id="node-input-broker">
</div>
<div class="form-row">
<label for="node-input-topic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
<input type="text" id="node-input-topic" data-i18n="[placeholder]common.label.topic">
</div>
<div class="form-row mqtt-form-row-cols2">
<label for="node-input-qos" class="mqtt-form-row-col1"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
<select id="node-input-qos" class="mqtt-form-row-col1">
<option value=""></option>
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
<label for="node-input-retain" class="mqtt-form-row-col2"><i class="fa fa-history"></i> <span data-i18n="mqtt.retain"></span></label>
<select id="node-input-retain" class="mqtt-form-row-col2" >
<option value=""></option>
<option value="false" data-i18n="mqtt.false"></option>
<option value="true" data-i18n="mqtt.true"></option>
</select>
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-input-userProps"><span data-i18n="mqtt.label.userProperties"></span></label>
<input type="text" id="node-input-userProps" style="width: calc(100% - 166px);">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-input-respTopic"><span data-i18n="mqtt.label.responseTopic"></span></label>
<input type="text" id="node-input-respTopic" style="width: calc(100% - 166px);">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-input-correl"><span data-i18n="mqtt.label.correlationData"></span></label>
<input type="text" id="node-input-correl" style="width: calc(100% - 166px);">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-input-contentType"><span data-i18n="mqtt.label.contentType"></span></label>
<input type="text" id="node-input-contentType" style="width: calc(100% - 166px);">
</div>
<div class="form-row mqtt-form-row-cols2 mqtt5 mqtt5-out">
<label for="node-input-expiry" class="mqtt-form-row-col1"><span data-i18n="mqtt.label.expiry"></span></label>
<input id="node-input-expiry" style="width: calc(100% - 166px);" class="mqtt-form-row-col1" >
</div>
<div class="form-row">
<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">
</div>
<div class="form-tips"><span data-i18n="mqtt.tip"></span></div>
</script>
<script type="text/html" data-template-name="mqtt-gem-broker">
<div class="form-row">
<label for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-config-input-name" data-i18n="[placeholder]common.label.name">
</div>
<div class="form-row">
<ul style="min-width: 600px; margin-bottom: 20px;" id="node-config-mqtt-broker-tabs"></ul>
</div>
<div id="node-config-mqtt-broker-tabs-content" style="min-height:150px;">
<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 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>
<input type="text" id="node-config-input-port" placeholder="1883 or ${ENV_VAR}" style="width:80px">
</div>
<div class="form-row">
<label for="node-config-input-autoConnect"><i class="fa fa-plug"></i> <span data-i18n="mqtt.label.auto-connect"></span></label>
<input type="text" id="node-config-input-autoConnect" placeholder="true/false or ${ENV_VAR}" style="width: 70%">
</div>
<div class="form-row">
<label for="node-config-input-usetls"><i class="fa fa-lock"></i> <span data-i18n="mqtt.label.use-tls"></span></label>
<input type="text" id="node-config-input-usetls" placeholder="true/false or ${ENV_VAR}" style="width: 70%">
<span id="node-config-row-tls" class="hide" style="margin-left: 10px;"><input style="width: 200px;" type="text" id="node-config-input-tls"></span>
</div>
<div class="form-row">
<label for="node-config-input-protocolVersion-select"><i class="fa fa-cog"></i> <span data-i18n="mqtt.label.protocolVersion"></span></label>
<select id="node-config-input-protocolVersion-select" style="width:70%;">
<option value="3">MQTT V3.1 (legacy)</option>
<option value="4">MQTT V3.1.1</option>
<option value="5">MQTT V5</option>
</select>
</div>
<div class="form-row">
<label for="node-config-input-protocolVersion-custom"><i class="fa fa-code"></i> <span data-i18n="mqtt.label.dynamicProtocol"></span></label>
<input type="text"
id="node-config-input-protocolVersion-custom"
name="protocolVersionCustom"
placeholder="Empty (not used) or env.var like ${MQTT_PROTOCOL}"
style="width:70%;" />
</div>
<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> <span data-i18n="mqtt.label.session"></span></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 class="form-row mqtt-persistence">
<label for="node-config-input-autoUnsubscribe" style="width: auto;">
<input type="checkbox" id="node-config-input-autoUnsubscribe" style="position: relative;vertical-align: bottom; top: -2px; width: 15px;height: 15px;">
<span id="node-config-input-autoUnsubscribe-label" data-i18n="mqtt.label.autoUnsubscribe"></span>
</label>
</div>
<div class="form-row mqtt5">
<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-sessionExpiry" style="width: 100px" >
</div>
</div>
</div>
<div class="form-row mqtt5">
<label style="width: 125px;" for="node-config-input-userProps"><span data-i18n="mqtt.label.userProperties"></span></label>
<input type="text" id="node-config-input-userProps" style="width: calc(100% - 166px);">
</div>
<br>
</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">
</div>
<div class="form-row">
<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>
<div id="mqtt-broker-tab-messages" style="display:none">
<div id="mqtt-broker-section-birth">
<div class="red-ui-palette-header">
<i class="fa fa-angle-down"></i><span data-i18n="mqtt.sections-label.birth-message"></span>
</div>
<div class="section-content" style="padding:10px 0 0 10px">
<div class="form-row">
<label style="width: 100px !important;" for="node-config-input-birthTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-birthTopic" data-i18n="[placeholder]mqtt.placeholder.birth-topic">
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-birthRetain"><i class="fa fa-history"></i> <span data-i18n="mqtt.label.retain"></span></label>
<select id="node-config-input-birthRetain" style="width:75px !important">
<option value="false" data-i18n="mqtt.false"></option>
<option value="true" data-i18n="mqtt.true"></option>
</select>
</div>
<div class="form-row">
<label style="width: 100px !important;" for="node-config-input-birthPayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-birthPayload" data-i18n="[placeholder]common.label.payload">
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-birthQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
<select id="node-config-input-birthQos" style="width:75px !important">
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
</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 id="mqtt-broker-section-close">
<div class="red-ui-palette-header">
<i class="fa fa-angle-down"></i><span data-i18n="mqtt.sections-label.close-message"></span>
</div>
<div class="section-content" style="padding:10px 0 0 10px">
<div class="form-row">
<label style="width: 100px !important;" for="node-config-input-closeTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-closeTopic" data-i18n="[placeholder]mqtt.placeholder.close-topic">
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-closeRetain"><i class="fa fa-history"></i> <span data-i18n="mqtt.label.retain"></span></label>
<select id="node-config-input-closeRetain" style="width:75px !important">
<option value="false" data-i18n="mqtt.false"></option>
<option value="true" data-i18n="mqtt.true"></option>
</select>
</div>
<div class="form-row">
<label style="width: 100px !important;" for="node-config-input-closePayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-closePayload" data-i18n="[placeholder]common.label.payload">
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-closeQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
<select id="node-config-input-closeQos" style="width:75px !important">
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
</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 id="mqtt-broker-section-will">
<div class="red-ui-palette-header">
<i class="fa fa-angle-down"></i><span data-i18n="mqtt.sections-label.will-message"></span>
</div>
<div class="section-content" style="padding:10px 0 0 10px">
<div class="form-row">
<label style="width: 100px !important;" for="node-config-input-willTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-willTopic" data-i18n="[placeholder]mqtt.placeholder.will-topic">
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-willRetain"><i class="fa fa-history"></i> <span data-i18n="mqtt.label.retain"></span></label>
<select id="node-config-input-willRetain" style="width:75px !important">
<option value="false" data-i18n="mqtt.false"></option>
<option value="true" data-i18n="mqtt.true"></option>
</select>
</div>
<div class="form-row">
<label style="width: 100px !important;" for="node-config-input-willPayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-willPayload" data-i18n="[placeholder]common.label.payload">
<label style="margin-left: 10px; width: 90px !important;" 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:75px !important">
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-will-delay"><span data-i18n="mqtt.label.willDelay"></span></label>
<input id="node-config-input-will-delay" style="width: calc(100% - 200px);">
</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>
</script>
<script type="text/javascript">
(function () {
var typedInputNoneOpt = {
value: 'none',
label: RED._("node-red:mqtt.label.none"),
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: RED._("node-red:mqtt.label.other"),
icon: "red/images/typedInput/az.svg"
}
];
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'
}
/**
* Test a topic string is valid for publishing
* @param {string} topic
* @returns `true` if it is a valid topic
*/
function validateMQTTPublishTopic(topic, opts) {
if (!topic || topic == "" || !/[\+#\b\f\n\r\t\v\0]/.test(topic)) {
return true;
}
return RED._("node-red:mqtt.errors.invalid-topic");
}
function setupTopicField(node, input) {
input.autoComplete({
minLength: 0,
completionPluginType: 'node-red-mqtt-topic-autocomplete-source',
context: {
node
}
})
}
RED.nodes.registerType('mqtt-gem-broker', {
category: 'config',
defaults: {
name: { value: "" },
broker: { value: "", required: true },
port: {
value: 1883, required: false,
label: RED._("node-red:mqtt.label.port"),
validate: RED.validators.number(true)
},
protocolVersionCustom: { value: "" },
tls: {
type: "tls-config", required: false,
label: RED._("node-red:mqtt.label.use-tls")
},
clientid: {
value: "", validate: function (v, opt) {
let ok = true;
if ($("#node-config-input-clientid").length) {
// Currently editing the node
let needClientId = !$("#node-config-input-cleansession").is(":checked")
if (needClientId) {
ok = (v || "").length > 0;
}
} else {
let needClientId = !(this.cleansession === undefined || this.cleansession)
if (needClientId) {
ok = (v || "").length > 0;
}
}
if (!ok) {
return RED._("node-red:mqtt.errors.invalid-client-id");
}
return true;
}
},
autoConnect: { value: "true" },
usetls: { value: "false" },
verifyservercert: { value: false },
compatmode: { value: false },
protocolVersion: { value: 4 },
protocolVersionCustom: { value: "" },
keepalive: {
value: 60,
label: RED._("node-red:mqtt.label.keepalive"),
validate: RED.validators.number(false)
},
cleansession: { value: true },
autoUnsubscribe: { value: true },
birthTopic: { value: "", validate: validateMQTTPublishTopic },
birthQos: { value: "0" },
birthRetain: { value: "false" },
birthPayload: { value: "" },
birthMsg: { value: {} },
closeTopic: { value: "", validate: validateMQTTPublishTopic },
closeQos: { value: "0" },
closeRetain: { value: "false" },
closePayload: { value: "" },
closeMsg: { value: {} },
willTopic: { value: "", validate: validateMQTTPublishTopic },
willQos: { value: "0" },
willRetain: { value: "false" },
willPayload: { value: "" },
willMsg: { value: {} },
userProps: { value: "" },
sessionExpiry: { value: 0 }
},
credentials: {
user: { type: "text" },
password: { type: "password" }
},
label: function () {
if (this.name) {
return this.name;
}
var b = this.broker;
if (!b) { b = "undefined"; }
var lab = "";
lab = (this.clientid ? this.clientid + "@" : "") + b;
if (b.indexOf("://") === -1) {
if (!this.port) { lab = lab + ":1883"; }
else { lab = lab + ":" + this.port; }
}
return lab;
},
oneditprepare: function () {
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();
}
});
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-messages",
label: this._("mqtt.tabs-label.messages")
});
function setUpSection(sectionId, v5Opts, isExpanded) {
var birthMessageSection = $("#mqtt-broker-section-" + sectionId);
var paletteHeader = birthMessageSection.find('.red-ui-palette-header');
var twistie = paletteHeader.find('i');
var sectionContent = birthMessageSection.find('.section-content');
function toggleSection(expanded) {
twistie.toggleClass('expanded', expanded);
sectionContent.toggle(expanded);
}
paletteHeader.on("click", function (e) {
e.preventDefault();
var isExpanded = twistie.hasClass('expanded');
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
var showBirthSection = this.birthTopic !== ""
|| this.willTopic === ""
&& this.birthTopic === ""
&& this.closeTopic == "";
setUpSection('birth', this.birthMsg, showBirthSection);
setUpSection('close', this.closeMsg, this.closeTopic !== "");
setUpSection('will', this.willMsg, this.willTopic !== "");
if (this.willMsg) {
$("#node-config-input-will-delay").val(this.willMsg.delay);
}
setTimeout(function () { tabs.resize(); }, 0);
if (typeof this.cleansession === 'undefined') {
this.cleansession = true;
$("#node-config-input-cleansession").prop("checked", true);
}
if (typeof this.autoUnsubscribe === 'undefined') {
this.autoUnsubscribe = true;
$("#node-config-input-autoUnsubscribe").prop("checked", true);
}
if (typeof this.usetls === 'undefined') {
this.usetls = "false";
$("#node-config-input-usetls").val("false");
}
if (typeof this.autoConnect === 'undefined') {
this.autoConnect = "true";
$("#node-config-input-autoConnect").val("true");
}
if (this.compatmode === 'true' || this.compatmode === true) {
delete this.compatmode;
this.protocolVersion = 4;
}
// Nella funzione oneditprepare, trova e sostituisci la gestione del protocolVersion
if (typeof this.protocolVersion === 'undefined') {
this.protocolVersion = 4;
this.protocolVersionCustom = "";
} else {
// Se protocolVersion non è uno dei valori standard, lo mettiamo nel campo custom
if (this.protocolVersion !== '3' && this.protocolVersion !== '4' && this.protocolVersion !== '5' &&
this.protocolVersion !== 3 && this.protocolVersion !== 4 && this.protocolVersion !== 5) {
this.protocolVersionCustom = this.protocolVersion;
this.protocolVersion = 4; // default per il select
}
}
$("#node-config-input-protocolVersion-select").val(this.protocolVersion || "4");
$("#node-config-input-protocolVersion-custom").val(this.protocolVersionCustom || "");
// Event handler for protocolVersion custom field
$("#node-config-input-protocolVersion-custom").on("change keyup paste input", function () {
// Mark node as dirty so Deploy button is activated
RED.nodes.dirty(true);
});
//
$("#node-config-input-cleansession").on("change", function () {
const useCleanSession = $("#node-config-input-cleansession").is(':checked');
if (useCleanSession) {
$("div.form-row.mqtt-persistence").hide();
} else {
$("div.form-row.mqtt-persistence").show();
}
});
$("#node-config-input-protocolVersion").on("change", function () {
var v5 = $("#node-config-input-protocolVersion").val() == "5";
if (v5) {
$("#node-config-input-cleansession-label").text(RED._("node-red:mqtt.label.cleanstart"))
$("div.form-row.mqtt5").show();
} else {
$("#node-config-input-cleansession-label").text(RED._("node-red:mqtt.label.cleansession"))
$("div.form-row.mqtt5").hide();
}
});
$("#node-config-input-protocolVersion").val(this.protocolVersion || "4");
$("#node-config-input-userProps").typedInput({
default: !this.userProps ? 'none' : 'json',
types: [typedInputNoneOpt, 'json']
});
$("#node-config-input-userProps").typedInput('value', this.userProps);
if (typeof this.keepalive === 'undefined') {
this.keepalive = 15;
$("#node-config-input-keepalive").val(this.keepalive);
}
if (typeof this.birthQos === 'undefined') {
this.birthQos = "0";
$("#node-config-input-birthQos").val("0");
}
if (typeof this.closeQos === 'undefined') {
this.willQos = "0";
$("#node-config-input-willQos").val("0");
}
if (typeof this.willQos === 'undefined') {
this.willQos = "0";
$("#node-config-input-willQos").val("0");
}
function updateTLSOptions() {
var usetlsVal = $("#node-config-input-usetls").val();
if (usetlsVal === "true" || usetlsVal === true) {
$("#node-config-row-tls").show();
} else {
$("#node-config-row-tls").hide();
}
}
updateTLSOptions();
$("#node-config-input-usetls").on("change keyup", 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 {
$("#node-config-input-clientid").attr("placeholder", node._("mqtt.placeholder.clientid-nonclean"));
}
$("#node-config-input-clientid").trigger("change");
}
setTimeout(updateClientId, 0);
$("#node-config-input-cleansession").on("click", function () {
updateClientId();
});
function updatePortEntry() {
var disabled = $("#node-config-input-port").prop("disabled");
if ($("#node-config-input-broker").val().indexOf("://") === -1) {
if (disabled) {
$("#node-config-input-port").prop("disabled", false);
}
}
else {
if (!disabled) {
$("#node-config-input-port").prop("disabled", true);
}
}
}
$("#node-config-input-broker").on("change", function () {
updatePortEntry();
});
$("#node-config-input-broker").on("keyup", function () {
updatePortEntry();
});
setTimeout(updatePortEntry, 50);
setTimeout(function () {
$("#node-config-input-protocolVersion").trigger("change");
}, 50);
},
oneditsave: function () {
// Save both the select value and the custom field value
this.protocolVersion = $("#node-config-input-protocolVersion-select").val();
this.protocolVersionCustom = $("#node-config-input-protocolVersion-custom").val();
//
var usetlsVal = $("#node-config-input-usetls").val();
if (usetlsVal !== "true" && usetlsVal !== true) {
$("#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.userProps = "";
const userPropsType = $("#node-config-input-userProps").typedInput("type");
if (userPropsType == "json") {
const userProps = $("#node-config-input-userProps").val();
if (userProps && typeof userProps === "string") {
this.userProps = userProps.trim();
}
}
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-gem in', {
category: 'network',
defaults: {
name: { value: "" },
topic: {
value: "",
validate: function (v, opt) {
var isDynamic = this.inputs === 1;
var topicTypeSelect = $("#node-input-topicType");
if (topicTypeSelect.length) {
isDynamic = topicTypeSelect.val() === 'dynamic'
}
if (isDynamic || ((!!v) && RED.validators.regex(/^(#$|(\+|[^+#]*)(\/(\+|[^+#]*))*(\/(\+|#|[^+#]*))?$)/)(v))) {
return true;
}
return RED._("node-red:mqtt.errors.invalid-topic");
}
},
qos: { value: "2" },
datatype: { value: "auto-detect", required: true },
broker: { type: "mqtt-gem-broker", required: true, label: RED._("node-red:mqtt.label.broker") },
// subscriptionIdentifier: {value:0},
nl: { value: false },
rap: { value: true },
rh: { value: 0 },
inputs: { value: 0 },
},
color: "#87CEEB",
inputs: 0,
outputs: 1,
icon: "bridge.svg",
paletteLabel: "mqtt gem in",
label: function () {
if (this.name) {
return this.name;
}
if (this.topicType !== "dynamic" && this.topic) {
return this.topic;
}
return "mqtt gem in"; // Nome predefinito invece di "mqtt"
},
labelStyle: function () {
return this.name ? "node_label_italic" : "";
},
oneditprepare: function () {
const node = this;
setupTopicField(this, $("#node-input-topic"));
const isV5Broker = function () {
var confNode = RED.nodes.node($("#node-input-broker").val());
return confNode && confNode.protocolVersion === "5";
}
const isDynamic = function () {
return $('#node-input-topicType').val() === "dynamic";
}
const updateVisibility = function () {
var v5 = isV5Broker();
var dynamic