node-red限速分流节点开发

2023-11-09

功能简述

  1. 此节点有一个输入,两个输出;
  2. 此节点可完成信息的限速分流功能,当信息高速输入时,节点进行限速处理(例:两秒一次),到指定时间后信息由一口输出,若未到指定时间(两秒)信息由二口输出。

节点设计

界面设计

节点界面中可设置信息传输速度,每多少秒限制多少条信息。
界面
代码如下:


<script type="text/html" data-template-name="delaytest">
    <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" date-i18n="[placeholder]node-red:common.label.name" autocomplete="off"
            dir placeholder="name">
    </div>

    <div id="rate-details">
        <div class="form-row">
            <label for="node-input-rate"><i class="fa fa-clock-o"></i> <span data-i18n="delay.rate">速度</span></label>
            <label for="node-input-rateUnits"><span data-i18n="delay.msgper"></span></label>
            <input type="text" id="node-input-nbRateUnits" placeholder="1"
                style="text-align:end; width:40px !important">
            <select id="node-input-rateUnits" style="width:90px !important">
                <option value="second" data-i18n="delay.label.units.second.singular"></option>
                <option value="minute" data-i18n="delay.label.units.minute.singular">分钟</option>
                <option value="hour" data-i18n="delay.label.units.hour.singular">小时</option>
                <option value="day" data-i18n="delay.label.units.day.singular"></option>
            </select>一条信息
        </div>
    </div>
</script>


<script type="text/javascript">
    RED.nodes.registerType('delaytest', {
        category: 'function',
        color: "#E6E0F8",
        defaults: {
            name: {
                value: "name"
            },
            rate: {
                value: "1",
                required: true,
                validate: function (v) {
                    return RED.validators.number(v) && (v >= 0);
                }
            },
            nbRateUnits: {
                value: "1",
                required: false,
                validate: RED.validators.regex(/\d+|/)
            },
            rateUnits: {
                value: "second"
            }
        },
        inputs: 1,
        outputs: 2,
        icon: "timer.svg",
        label: function () {
            if (this.name) {
                return this.name;
            }
            var rate = this.rate + " msg/" + (this.rateUnits ? (this.nbRateUnits > 1 ? this.nbRateUnits :
                '') + this.rateUnits.charAt(0) : "s");
            return this._("delay.label.limit") + " " + rate;
        },
        labelStyle: function () {
            return this.name ? "node_label_italic" : "";
        },
        oneditprepare: function () {
            var node = this;
            $("#node-input-rate").spinner({
                min: 1
            });
            $("#node-input-nbRateUnits").spinner({
                min: 1
            });
            $("#node-input-nbRateUnits").on('change keyup', function () {
                var $this = $(this);
                var val = parseInt($this.val());
                var type = "singular";
                if (val > 1) {
                    type = "plural";
                }
                if ($this.attr("data-type") == type) {
                    return;
                }
                $this.attr("data-type", type);
                $("#node-input-rateUnits option").each(function () {
                    var $option = $(this);
                    var key = "delay.label.units." + $option.val() + "." + type;
                    $option.attr('data-i18n', 'node-red:' + key);
                    $option.html(node._(key));
                });
            });
        }
    });
</script>

功能设计

这里主要参考官方delay节点中的限速部分代码。
代码如下:

module.exports = function (RED) {
    "use strict";
    function DelatTestNode(n) {
        RED.nodes.createNode(this, n);
        this.rateUnits = n.rateUnits;
        // 速率计时时间单位选项
        if (n.rateUnits === "minute") {
            this.rate = (60 * 1000) / n.rate;
        } else if (n.rateUnits === "hour") {
            this.rate = (60 * 60 * 1000) / n.rate;
        } else if (n.rateUnits === "day") {
            this.rate = (24 * 60 * 60 * 1000) / n.rate;
        } else { // Default to seconds
            this.rate = 1000 / n.rate;
        }
        // 规定限制速率:每条信息‘nbRateUnite’秒
        this.rate *= (n.nbRateUnits > 0 ? n.nbRateUnits : 1);
        this.name = n.name;
        this.buffer = [];
        this.intervalID = -1;
        var node = this;
        // reportDepth
        node.reportDepth = function () {
            if (!node.busy) {
                // 赋值node.busy以下函数的运行时间
                node.busy = setTimeout(function () {
                    // 判断node.buffer.length长度是否大于0,即输入的是否为正常字符串
                    if (node.buffer.length > 0) {
                        //显示nodered节点状态
                        node.status({
                            text: node.buffer.length
                        });
                    } else {
                        node.status({});
                    }
                    node.busy = null;
                }, 500);
            }
        }
        // 限制速率、每一个topic函数
        node.intervalID = setInterval(function () {
            while (node.buffer.length > 0) { // send the whole queue
                var msg1 = null;
                var msg2 = {
                    payload: node.buffer.shift()
                };
                node.send([msg1, msg2])
            }
            node.reportDepth();
        }, node.rate);

        node.on("input", function (msg) {
            if (msg.hasOwnProperty("reset")) {
                if (node.intervalID !== -1) {
                    clearInterval(node.intervalID);
                    node.intervalID = -1;
                }
                delete node.lastSent;
                node.buffer = [];
                node.status({
                    text: "reset"
                });
                return;
            }
            var timeSinceLast;

            timeSinceLast = process.hrtime(node.lastSent);
            if (((timeSinceLast[0] * 1000000000) + timeSinceLast[1]) > (node.rate * 1000000)) {
                node.lastSent = process.hrtime();
                var msg1 = null;
                var msg2 = {
                    payload: msg.payload
                };
                node.send([msg2, msg1]);
            } else {
                var msg1 = null;
                var msg2 = {
                    payload: msg.payload
                };
                node.send([msg1, msg2]);
            }
        });
        node.on("close", function () {
            clearInterval(node.intervalID);
            node.buffer = [];
            node.status({});
        });
    }
    RED.nodes.registerType("delaytest", DelatTestNode);
}

功能实现

串行总线(RS485)由于其非平衡传输特性的限制,广泛应用主从MODBUS RTU(ASCII)协议。主从协议严格遵循请求应答机制,尤其在主机向总线中各从机查询数据时,需要逐个设备节点、逐片寄存器发起请求。实际应用中称之为MODBUS总线数据轮询。

基于此节点的分流限速功能,可用于不同采集周期情况下的多设备数据轮询。如下图所示:
采集
假设在某应用场景下,三个设备分别需要每一秒,两秒,三秒采集一次数据,各设备按照指定周期时间采集数据,为避免占用数据传输总线冲突,当设备采集时间相同时,切换为轮询的方式依次采集数据。

即在第一秒时,信息传递路径为:
第一秒
第二秒时,信息传递路径为:
第二秒
第三秒时,信息传递路径为:
第三秒
之后的时间以此类推,在此基础上也可以添加更多设备或设置其他采集周期的设备。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

node-red限速分流节点开发 的相关文章