node-red-contrib-tasmota
Version:
Node-RED integration for Tasmota flashed devices
202 lines (196 loc) • 8.96 kB
HTML
<script type="text/html" data-template-name="Tasmota Sensor">
<div class="form-row">
<ul id="node-input-tasmota-tabs"></ul>
</div>
<div id="node-input-tabs-content">
<div id="tasmota-settings-tab" style="display:none">
<div class="form-row">
<label for="node-input-broker"><i class="fa fa-globe"></i> Broker</label>
<input type="text" id="node-input-broker">
</div>
<div class="form-row">
<label for="node-input-device"><i class="fa fa-dot-circle-o"></i> Device</label>
<input type="text" id="node-input-device" placeholder="Device id (topic)">
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-row">
<label for="node-input-uidisabler"><i class="fa fa-bar-chart"></i> Dashboard</label>
<label for="node-input-uidisabler" style="width:70%">
<input type="checkbox" id="node-input-uidisabler" style="display:inline-block; width:auto; vertical-align:baseline;">
Send enable/disable message
</label>
</div>
<hr>
<div class="form-row">
<label for="node-input-outputTopic"><i class="fa fa-tag"></i> Topic</label>
<input type="text" id="node-input-outputTopic" placeholder="Set the topic for output messages">
</div>
<label for="node-input-rule-container">Output channels payload:</label>
<div class="form-row node-input-rule-container-row">
<input type="hidden" id="node-input-outputs">
<ol id="node-input-rule-container"></ol>
</div>
</div>
<div id="tasmota-advanced-tab" style="display:none">
<div class="form-row">
<label for="node-input-fullTopic"><i class="fa fa-wrench"></i> Full topic</label>
<input type="text" id="node-input-fullTopic" placeholder="Full topic (Default: %prefix%/%topic%/)">
</div>
<div class="form-row">
<label for="node-input-cmndPrefix"><i class="fa fa-comment"></i> cmnd</label>
<input type="text" id="node-input-cmndPrefix" placeholder="Command topic prefix (Default: cmnd)">
</div>
<div class="form-row">
<label for="node-input-statPrefix"><i class="fa fa-comment"></i> stat</label>
<input type="text" id="node-input-statPrefix" placeholder="Stat topic prefix (Default: stat)">
</div>
<div class="form-row">
<label for="node-input-telePrefix"><i class="fa fa-comment"></i> tele</label>
<input type="text" id="node-input-telePrefix" placeholder="Telemetry topic prefix (Default: tele)">
</div>
<div class="form-row">
<label for="node-input-qos"><i class="fa fa-empire"></i> QoS</label>
<select id="node-input-qos" style="width:120px !important">
<option value="" selected disabled hidden>1</option>
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
<i class="fa fa-history"></i> Retain
<select id="node-input-retain" style="width:120px !important">
<option value="" selected disabled hidden>false</option>
<option value="false">false</option>
<option value="true">true</option>
</select>
</div>
</div>
</div>
</script>
<script type="text/html" data-help-name="Tasmota Sensor">
<p>Connect a <b>Sensor</b> device running the <b>Tasmota</b> firmware.</p>
<h3>Inputs</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">any</span></dt>
<dd>any input received will trigger a sensor data request to the device.</dd>
</dl>
<h3>Outputs</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">object</span></dt>
<dd>the complete JSON object as received from the Tasmota device. Unless
you have configured outputs using JSONata expressions.</dd>
</dl>
<h3>Details</h3>
<p>This node read sensors data from the device.<p>
<p>To combine more functionality from the same device (switch, sensor, etc..)
use more than one node connected to the same device.</p>
<p>Values are published as output on every telemetry messagge received from
the device. </p>
<p>Number of outputs can be configured, for each channel an expression
must be given and is used to extract a piece of value,
ex: <code>AM2301.Temperature</code>. Complex objects can also be created
using JSONata expressions.<p>
<p>Any messagge received in input will trigger a fresh-value-request
to the device, thus you can easily attach a repeating injection to receive
the sensor data at an higher frequency than the normal Tasmota telemetry
configuration.</p>
<p>In the Avanced tab you can customize the topic format for special cases,
the default values should work for a default Tasmota installation.</p>
<p>Input messagges are NOT forwarded to the output.</p>
</script>
<script type="text/javascript">
RED.nodes.registerType("Tasmota Sensor", {
category: "tasmota",
color: "#28AFB0",
defaults: {
// common basic
broker: { type: "tasmota-mqtt-broker", required: true },
device: { value: "", required: true },
name: { value: "" },
outputs: { value: 1 },
uidisabler: { value: false },
// common advanced
fullTopic: { value: "" },
cmndPrefix: { value: "" },
statPrefix: { value: "" },
telePrefix: { value: "" },
qos: { value: "1" }, // NOTE: always stored as string
retain: { value: "false" }, // NOTE: always stored as string
// node specific
rules: { value:[] },
outputTopic: { value: "" }
},
icon: "contrib-tasmota-sensor.svg",
paletteLabel: 'sensor',
inputs: 1,
outputs: 1,
label: function() {
return this.name || this.device || "Tasmota Sensor"
},
labelStyle: function() {
return this.name ? "node_label_italic" : ""
},
outputLabels: function(index) {
if (this.outputs && this.outputs > 1) {
return 'Output ' + (index+1)
}
},
oneditprepare: function () {
// initialize tabs
let tabs = RED.tabs.create({
id: "node-input-tasmota-tabs",
onchange: function (tab) {
$("#node-input-tabs-content").children().hide()
$("#" + tab.id).show()
}
})
// populate tabs
tabs.addTab({ id: "tasmota-settings-tab", label: "Settings" })
tabs.addTab({ id: "tasmota-advanced-tab", label: "Advanced" })
// initialize editable list
$("#node-input-rule-container").css('min-height','250px').editableList({
sortable: true,
removable: true,
addItem: function(container, i, opt) {
const rule = opt.r
const row = $('<div/>').appendTo(container)
const tinput = $('<input/>', {class:"node-input-rule-exp-value",
type:"text", style:"width:90%;"})
.val(rule).appendTo(row)
.typedInput({default:'jsonata', types:['jsonata']})
const finalspan = $('<span/>',{style:"float: right;margin-top: 6px;"}).appendTo(row)
finalspan.append(' → <span class="node-input-rule-index">'+(i+1)+'</span> ')
},
sortItems: function(rules) {
const items = $("#node-input-rule-container").editableList('items')
items.each(function(i) {
$(this).find(".node-input-rule-index").html(i + 1)
})
},
removeItem: function(opt) {
const items = $("#node-input-rule-container").editableList('items')
items.each(function(i) {
$(this).find(".node-input-rule-index").html(i + 1)
})
},
})
// populate editable list
for (let i = 0; i < this.rules.length; i++) {
const rule = this.rules[i]
$("#node-input-rule-container").editableList('addItem', {r: rule, i: i})
}
},
oneditsave: function() {
const items = $("#node-input-rule-container").editableList('items')
const node = this
node.rules = []
items.each(function(i) {
const rule = $(this).find(".node-input-rule-exp-value").typedInput('value')
node.rules.push(rule)
})
$('#node-input-outputs').val(node.rules.length || 1)
}
})
</script>