node-red-contrib-yotta-gpio
Version:
Yotta GPIO API nodes for Node-RED
485 lines (444 loc) • 16 kB
HTML
<!-- <style>
.input-error {
border: 2px solid red !important;
}
</style> -->
<script type="text/html" data-template-name="Write_DO">
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-row">
<label for="node-input-model"><i class="fa fa-cube"></i> 產品型號</label>
<select id="node-input-model"></select>
</div>
<div class="form-row">
<label for="node-input-modelqty"><i class="fa fa-sliders"></i> 輸出</label>
<select id="node-input-modelqty"></select>
</div>
<div class="form-row">
<label for="node-input-modbusid"><i class="fa fa-id-badge"></i> Modbus ID</label>
<input type="text" id="node-input-modbusid">
</div>
<div class="form-row">
<label for="node-input-modbusqty"><i class="fa fa-sort-numeric-asc"></i> 數量</label>
<input type="text" id="node-input-modbusqty">
</div>
<div class="form-row">
<label for="node-input-modbusaddr"><i class="fa fa-map-marker"></i> 起始位址</label>
<input type="text" id="node-input-modbusaddr" readonly >
</div>
<!-- <fieldset style="border: 1px solid #ccc; padding: 10px; border-radius: 5px;">
<input type="checkbox" id="chbx" name="agree" value="Yes!" />
<label for="chbx">I agree</label>
</fieldset> -->
</script>
<script type="text/javascript">
RED.nodes.registerType('Write_DO', {
category: 'YOTTA GPIO',
color: '#FFD700',
paletteLabel: "Write-DO", // 左側欄位顯示的節點名稱
defaults: {
name: { value: "" },
model: { value: "" },
modelQty: { value: "" },
modbusId: { value: "1" },
modbusQty:{ value: "1" },
modbusAddr: { value: "" }
},
inputs: 1,
outputs: 1,
align: "right",
icon: "serial.svg",
label: function () {
return this.name || this.model;
},
oneditprepare: function () {
const $model = $("#node-input-model");
const $modelqty = $("#node-input-modelqty");
const $modbusid = $("#node-input-modbusid");
const $modbusqty = $("#node-input-modbusqty");
const $modbusaddr = $("#node-input-modbusaddr");
var savedModel = this.model;
var savedQty = this.modelQty;
var savedModebusId = this.modbusId;
var savedModbusQty = this.modbusQty;
var savedModbusAddr = this.modbusAddr;
var moduleData;
debugger; // 在瀏覽器中執行Ctr+Shit+i開啟除錯畫面,可以針對html中的程式除錯
$.getJSON("Write_DO/0", function (data) { //向後端獲取產品訊息
moduleData = data;
// 填入型號選單
//$.each(moduleData, function (modelName,modelInfo) {
// if(modelInfo.DO > 0){
// $model.append($("<option></option>").val(modelName).text(modelName));
// }
//});
$.each(moduleData, function (categoryName, models) {
const $optgroup = $("<optgroup></optgroup>")
.attr("label", categoryName);
$.each(models, function (modelName, modelInfo) {
if (modelInfo.DO > 0) {
$optgroup.append(
$("<option></option>").val(modelName).text(modelName)
);
}
});
// 如果 optgroup 下有 option 再加入
if ($optgroup.children().length > 0) {
$model.append($optgroup);
}
});
if (!savedModel) {
savedModel = $model.find("option:first").val();
} else $model.val(savedModel); //若savedModel非空,載入model欄位初值
if (savedQty) $modelqty.val(savedQty); //若savedQty非空,載入Qty欄位初值
if (savedModebusId) $modbusid.val(savedModebusId); //若savedId非空,載入modbusid欄位初值
if (savedModbusQty) $modbusqty.val(savedModbusQty); //若savedModbusQty非空,載入modbusqty欄位初值
$model.on("change", function () {
savedModel = $(this).val();
savedQty = 0;
updateQtyAndAddress(savedModel);
});
$modelqty.on("change", function () {
savedQty = $(this).val();
//const addr = moduleData[savedModel].address["DO"]+Number(savedQty);
const modelInfo = findModelInfo(savedModel);
const addr = modelInfo.address["DO"] + Number(savedQty);
$modbusaddr.val(addr !== null ? addr : "N/A");
const val = $(this).val().trim();
if (val === "" || val === "0") {
$(this).addClass("input-error");
} else {
$(this).removeClass("input-error");
}
});
$modbusid.on("keyup", function () { //輸入中(keyup)或輸入完畢後離開欄位(change),都能觸發驗證或處理邏輯。
const val = Number($(this).val().trim());
if (val == 0 || isNaN(val) ) { //判斷modbus ID欄位內容是否合法,不合法將欄位邊框變紅色
$(this).addClass("input-error");
} else {
$(this).removeClass("input-error");
}
});
$modbusqty.on("keyup", function () { //輸入中(keyup)或輸入完畢後離開欄位(change),都能觸發驗證或處理邏輯。
const val = Number($(this).val().trim());
if (val == 0 || isNaN(val)) { //判斷modbus 數量欄位內容是否合法,不合法將欄位邊框變紅色
$(this).addClass("input-error");
} else {
$(this).removeClass("input-error");
}
});
// 觸發初始化選項
if (savedModel) {
updateQtyAndAddress(savedModel);
//if(savedModebusId == "") $modbusid.val("1");
//if(savedModbusQty == "") $modbusqty.val("1");
$modbusid.trigger("keyup");
$modbusqty.trigger("keyup");
}
})
.fail(function() {
console.log( "error" );
});
function findModelInfo(modelName) {
for (const category in moduleData) {
if (moduleData[category][modelName]) {
return moduleData[category][modelName];
}
}
return null;
}
function updateQtyAndAddress(model) { //將指定model的輸出/入類別編號填入option選單內。
$modelqty.empty(); //清空<select id="node-input-modelqty"> 這個欄位中的所有 <option>,以便重新建立。
//const count = moduleData[model]["DO"]-1;
//const addr = moduleData[model].address["DO"] + Number(savedQty);
const modelInfo = findModelInfo(model);
if (!modelInfo) return;
const count = modelInfo["DO"] - 1;
const addr = modelInfo.address["DO"] + Number(savedQty);
for (let i = 0; i <= count; i++) {
$modelqty.append($("<option></option>").val(i).text("DO " + i));
}
if (savedQty) $modelqty.val(savedQty);
$modbusaddr.val(addr !== null ? addr : "N/A");
}
},
oneditsave: function () {
this.name = $("#node-input-name").val();
this.model = $("#node-input-model").val();
this.modelQty = $("#node-input-modelqty").val();
this.modbusId = $("#node-input-modbusid").val();
this.modbusAddr = $("#node-input-modbusaddr").val();
this.modbusQty = $("#node-input-modbusqty").val();
},
oneditresize: function (size) {
}
});
</script>
<script type="text/x-red" data-help-name="Write_DO">
<p>
<strong>Write_DO</strong> 節點用於將指定數值寫入 DO (Digital Output) 腳位,並與 <code>Modbus-Flex-Write</code> 節點配合使用。
</p>
<h3>功能說明</h3>
<ul>
<li><strong>產品型號</strong>:支援多種 Yotta 模組型號</li>
<li><strong>輸出腳位</strong>:可選擇 DO 腳位 (例如 DO 0、DO 1 等)</li>
<li><strong>Modbus ID</strong>:目標設備的通訊位址</li>
<li><strong>數量</strong>:寫入的腳位數量</li>
</ul>
<h3>注意事項</h3>
<ul>
<li>Modbus ID、腳位數量與起始位址必須正確對應實際設備</li>
<li>務必與 <code>Modbus-Flex-Write</code> 節點搭配使用</li>
<li>未填寫必要欄位將導致資料封包錯誤</li>
<li>當寫入數量大於 1 時,注入的<code>msg.payload</code> 必須為 <code>array[]</code> 格式,例如:<code>[1, 1]</code></li>
</ul>
<h3>使用範例</h3>
<p>將 DO 0~3 設為 High/Low:</p>
<pre><code style="font-size: smaller">
[
{
"id": "10f36070430118c5",
"type": "tab",
"label": "流程4",
"disabled": false,
"info": "",
"env": []
},
{
"id": "f846e7029f3192d8",
"type": "inject",
"z": "10f36070430118c5",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "0",
"payloadType": "num",
"x": 170,
"y": 100,
"wires": [
[
"1302bcc2eefc651e"
]
]
},
{
"id": "088232fa064cdf4f",
"type": "debug",
"z": "10f36070430118c5",
"name": "debug 49",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 800,
"y": 100,
"wires": []
},
{
"id": "0958a9be2de05815",
"type": "modbus-flex-write",
"z": "10f36070430118c5",
"name": "",
"showStatusActivities": false,
"showErrors": true,
"server": "6aa025f7928cfbeb",
"emptyMsgOnFail": false,
"keepMsgProperties": false,
"x": 590,
"y": 100,
"wires": [
[
"088232fa064cdf4f"
],
[]
]
},
{
"id": "d35d353dcf03406b",
"type": "inject",
"z": "10f36070430118c5",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "1",
"payloadType": "num",
"x": 170,
"y": 140,
"wires": [
[
"1302bcc2eefc651e"
]
]
},
{
"id": "56ebf44ab51af0f3",
"type": "inject",
"z": "10f36070430118c5",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "[1,1,1,1]",
"payloadType": "json",
"x": 180,
"y": 180,
"wires": [
[
"52ed0f4906d8509c"
]
]
},
{
"id": "6e1c481a11adcb51",
"type": "inject",
"z": "10f36070430118c5",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "[0,0,0,0]",
"payloadType": "json",
"x": 180,
"y": 220,
"wires": [
[
"52ed0f4906d8509c"
]
]
},
{
"id": "1302bcc2eefc651e",
"type": "Write_DO",
"z": "10f36070430118c5",
"name": "",
"model": "A-1060",
"modelQty": "0",
"modbusId": "1",
"modbusQty": "1",
"modbusAddr": "16",
"x": 360,
"y": 100,
"wires": [
[
"0958a9be2de05815"
]
]
},
{
"id": "52ed0f4906d8509c",
"type": "Write_DO",
"z": "10f36070430118c5",
"name": "",
"model": "A-1060",
"modelQty": "0",
"modbusId": "2",
"modbusQty": "4",
"modbusAddr": "16",
"x": 360,
"y": 200,
"wires": [
[
"0958a9be2de05815"
]
]
},
{
"id": "97d366b6b98b108e",
"type": "comment",
"z": "10f36070430118c5",
"name": "單點寫入",
"info": "",
"x": 360,
"y": 60,
"wires": []
},
{
"id": "9343c6786ff87837",
"type": "comment",
"z": "10f36070430118c5",
"name": "多點寫入",
"info": "",
"x": 360,
"y": 160,
"wires": []
},
{
"id": "6aa025f7928cfbeb",
"type": "modbus-client",
"name": "",
"clienttype": "simpleser",
"bufferCommands": true,
"stateLogEnabled": false,
"queueLogEnabled": false,
"tcpHost": "127.0.0.1",
"tcpPort": "502",
"tcpType": "DEFAULT",
"serialPort": "COM8",
"serialType": "RTU-BUFFERD",
"serialBaudrate": "9600",
"serialDatabits": "8",
"serialStopbits": "1",
"serialParity": "none",
"serialConnectionDelay": "100",
"serialAsciiResponseStartDelimiter": "0x3A",
"unit_id": "1",
"commandDelay": "1",
"clientTimeout": "1000",
"reconnectOnTimeout": true,
"reconnectTimeout": "2000",
"parallelUnitIdsAllowed": true
}
]
</pre></code>
</script>