产品定价 立即试用
目录
如何将 RN172plus series 连接至 ThingsBoard?
  • Hardware type: Sensors
  • Connectivity: Wi-Fi, MODBUS TCP, HTTP, HTTPS
  • Industry: Smart Cities, Smart Buildings, Environmental Monitoring, Industrial Manufacturing
  • Use cases: Environment Monitoring, Smart Office, Smart Retail, Health Care
  • Platforms: Community Edition, Professional Edition, Cloud

概述

RADIONODE出品的 RN172WCD 是一款多功能Wi-Fi传感器数据发射器,用于工业、商业及实验室环境的实时监测。
支持多种UA系列传感器,包括气体检测(CO₂、O₂、NH₃ 等)、温度传感器(PT100、热电偶)及模拟变送器(4–20 mA、0–1 V),可灵活部署于各类应用。
通过Wi-Fi(IEEE 802.11 b/g)、MODBUS TCP和HTTP/HTTPS,可无缝将数据传送至Radionode365等云平台、本地服务器或PLC集中监控。
内置蜂鸣器、双色LED指示及4位数码管,用于实时读数与告警。
RN172WCD支持通过Telnet远程配置,具备SMS与语音告警等告警功能,适用于气体监测、HVAC系统、工业自动化等安全关键场景。

前置条件

继续本指南前需准备以下内容:

在ThingsBoard中创建设备

为简单起见,我们将通过UI手动创建设备。

  • 登录ThingsBoard实例,导航到实体,然后打开设备页面。
  • 点击表格右上角的+图标,选择添加新设备
  • 输入设备名称,例如My Device。其他字段保持默认值即可。
  • 点击添加创建设备。

设备已成功添加。

image

安装所需Payload解码器

添加设备后,需要创建一个集成,以建立设备与ThingsBoard平台的连接。

  • 点击集成选项卡,然后点击“+”按钮开始添加集成。

image

  • 点击集成选项卡,选择集成类型开始添加集成。

image

  • 这里我们为RN172设备选择HTTP协议。

image

  • 然后为集成输入一个名称。

image

下一步是为设备创建数据转换器

  • 为数据转换器输入名称
  • 点击解码配置选择js类型,并添加以下代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
/**
 * Helper function to decode raw payload bytes to a string using a simple loop.
 * This method is more robust and compatible with older JS environments.
 */
function decodeToString(payload) {
    var text = "";
    var i = 0;
    while (i < payload.length) {
        text += String.fromCharCode(payload[i]);
        i++;
    }
    return text;
}

/**
 * Helper function to decode raw payload bytes to a JSON object.
 * It safely parses the string and returns a JSON object.
 */
function decodeToJson(payload) {
    try {
        var str = decodeToString(payload);
        return JSON.parse(str);
    } catch (e) {
        return null;
    }
}

/**
 * A custom parser to handle URL-encoded payloads.
 */
function parseUrlEncoded(payload) {
    var data = {};
    var bodyStr = decodeToString(payload).trim();
    if (bodyStr.indexOf('=') !== -1) {
        var pairs = bodyStr.split("&");
        var i = 0;
        while (i < pairs.length) {
            var parts = pairs[i].split("=");
            if (parts.length === 2) {
                var key = decodeURIComponent(parts[0].trim());
                var value = decodeURIComponent((parts[1] || "").trim());
                data[key] = value;
            }
            i++;
        }
    }
    return data;
}

// --- Main ThingsBoard Decode Function ---
function decodePayload(payload, metadata) {
    var deviceName = "Unknown_Device";
    var attributes = {};
    var telemetry = {};
    var telemetryTimestamp = null;
    var data = null;
    var detectedModel = null;

    // --- Model Lookup Table ---
    const ua_models_js = {
        "UA58-KFG": ["CO", "O2", "H2S", "CO2"],
        "UA58-CO2": ["CO2", "TEMP", "RH"],
        "UA58-DFG": ["CO", "CH2O", "C6H6"],
        "UA58-LEL": ["LEL", "TEMP", "RH", "CLAS"],
        "UA58-APC": ["CO2", "O3", "TEMP", "RH"],
        "UA50": ["TVOC", "ECO2"],
        "UA52-CO2": ["CO2", "TEMP"],
        "UA52-O2": ["O2", "TEMP"],
        "UA53-CO": ["CO", "TEMP", "RH"],
        "UA53-H2S": ["H2S", "TEMP", "RH"],
        "UA53-O3": ["O3", "TEMP", "RH"],
        "UA53-SO2": ["SO2", "TEMP", "RH"],
        "UA53-NO2": ["NO2", "TEMP", "RH"],
        "UA54-NH3": ["NH3", "TEMP", "RH"],
        "UA54-H2S": ["H2S", "TEMP", "RH"],
        "UA54-C2H4": ["C2H4", "TEMP", "RH"],
        "UA54-EO": ["EO", "TEMP", "RH"],
        "UA54-H2": ["H2", "TEMP", "RH"],
        "UA54-HCL": ["HCL", "TEMP", "RH"],
        "UA54-NO": ["NO", "TEMP", "RH"],
        "UA54-CL2": ["CL2", "TEMP", "RH"],
        "UA54-O2": ["O2", "TEMP", "RH"],
        "UA54-VOC": ["VOC", "TEMP", "RH"],
        "UA10": ["TEMP", "RH"],
        "UA11": ["TEMP", "TEMP"],
        "UA12": ["TEMP", "TEMP"],
        "UA13": ["TEMP"],
        "UA20A": ["mA", "mA"],
        "UA20B": ["mA"],
        "UA20C": ["mV", "mV"],
        "UA20D": ["Puls"],
        "UA20E": ["CH1", "CH2", "CH3", "CH4", "CH5", "CH6"],
        "UA59-CO2": ["CO2", "TEMP"],
        "UA60-PMVT": ["PM25", "PM10", "PM01", "TVOC", "TEMP", "RH"],
        "UA-DEVICE": ["TEMP", "RH"],
        "RN400-PG": [],
        "RN172WC": []
    };

    // --- Step 1: Payload Parsing ---
    var inputString = decodeToString(payload).trim();
    var atcqMatch = inputString.match(/ATCQ\s+([^,]+),([^,]+),([^,]+),([^,]+)/);
    
    if (atcqMatch) {
        // ATCQ payload format
        data = {};
        data.co2 = parseFloat(atcqMatch[1]);
        data.o3 = parseFloat(atcqMatch[2]);
        data.temperature = parseFloat(atcqMatch[3]);
        data.humidity = parseFloat(atcqMatch[4]);
        detectedModel = 'UA58-APC';
    } else {
        // Other payload formats (JSON, URL-encoded)
        data = decodeToJson(payload);
        if (!data) {
            data = parseUrlEncoded(payload);
        }
    }

    if (!data || Object.keys(data).length === 0) {
        return null;
    }

    // --- Step 2: Model Identification and Override ---
    var originalSModel = data.model || data.SMODEL;
    detectedModel = detectedModel || originalSModel;

    // Override the model if the payload structure matches UA58-APC.
    if (detectedModel === 'UA-DEVICE' && data.C000) {
        var channelData = data.C000.split('|').filter(x => x.trim() !== '');
        if (channelData.length === 5) {
            detectedModel = 'UA58-APC';
        }
    }

    var modelVars = ua_models_js[detectedModel];

    // --- Step 3: Process Telemetry and Attributes ---
    if (data.mac) {
        deviceName = data.mac;
        attributes.mac = data.mac;
    }
    if (data.ver) attributes.firmware = data.ver;
    if (originalSModel) attributes.SMODEL = originalSModel;
    if (data.model) attributes.model = data.model;
    if (detectedModel) attributes.detected_model = detectedModel;
    if (data.ip) attributes.ip = data.ip;
    if (data.splrate) attributes.samplingRate = parseFloat(data.splrate);
    if (data.rsti) attributes.rsti = parseFloat(data.rsti);
    if (data.interval) attributes.transmitInterval = parseFloat(data.interval);
    if (data.tags) attributes.tags = data.tags;

    // Process dynamic channels based on the detected model
    if (detectedModel && modelVars) {
        var dynamicKey;
        for (dynamicKey in data) {
            if (dynamicKey.match(/^(C|P|CH)\d+/)) {
                var channelData = data[dynamicKey].split('|').filter(x => x.trim() !== '');
                if (channelData.length > 1) {
                    telemetryTimestamp = parseInt(channelData[0]) * 1000;
                    var i = 0;
                    while (i < modelVars.length) {
                        var varName = modelVars[i];
                        if (varName !== '----') {
                            var value = parseFloat(channelData[i + 1]);
                            if (!isNaN(value)) {
                                telemetry[varName.toLowerCase()] = value;
                            }
                        }
                        i++;
                    }
                }
            }
        }
    }

    // Process static keys
    if (data.co2 !== undefined) telemetry.co2 = parseFloat(data.co2);
    if (data.o3 !== undefined) telemetry.o3 = parseFloat(data.o3);
    if (data.temperature !== undefined) telemetry.temperature = parseFloat(data.temperature);
    if (data.humidity !== undefined) telemetry.humidity = parseFloat(data.humidity);
    if (data.sig !== undefined) telemetry.signal = parseFloat(data.sig);
    if (data.bat !== undefined) telemetry.battery = parseFloat(data.bat);
    if (data.analog_1 !== undefined) telemetry.analog_1 = parseFloat(data.analog_1);
    if (data.analog_2 !== undefined) telemetry.analog_2 = parseFloat(data.analog_2);

    // Process RN172WC 'tags' payload separately
    if (detectedModel === "RN172WC" && data.tags) {
        var tagValues = data.tags.split('|').filter(s => s.trim() !== '');
        if (tagValues.length >= 2) {
            telemetry.temperature = parseFloat(tagValues[0].trim());
            telemetry.humidity = parseFloat(tagValues[1].trim());
        }
    }

    // If no telemetry values are found, add a heartbeat to ensure a valid payload
    if (Object.keys(telemetry).length === 0) {
        telemetry.heartbeat = Date.now();
    }
    
    // --- Step 4: Construct the final output object in the correct format ---
    var result = {
        deviceName: deviceName,
        telemetry: {}
    };

    var finalTelemetryTs = telemetryTimestamp || Date.now();
    for (var key in telemetry) {
        result.telemetry[key] = telemetry[key];
    }

    for (var key in attributes) {
        result.telemetry[key] = attributes[key];
    }
    
    // Return the formatted result for ThingsBoard.
    return result;
}

return decodePayload(payload, metadata);

image

  • 然后完成集成配置。

image

image

连接设备到ThingsBoard

  • 下载 RadioNode终端程序
  • 运行RadioNode终端程序
  • 输入密码radionode114并进入控制台菜单。

image

  • 在网络设置中可以添加Wi-Fi SSID和密码。

image)

  • 进入“2. System Setup”菜单,选择“B. Set Destination of HTTP”。
  • 在三个目标地址中选择“2:CUSTOMER_V2”。

这表示数据将发送到自定义服务器V2。

image

  • 从ThingsBoard的集成选项卡中复制HTTP端点URL,用于在Radionode终端程序中设置。

image

image

进入“4. HTTP Destination Setup”菜单,选择“A. Set Host URL:thingsboard.cloud”,然后分别设置“D.Set HTTP DATAIN”、“E.Set HTTP TIMESTAMP”、“F.Set HTTP BACKUPIN”为集成中的端点地址。

在ThingsBoard上查看数据

设备连接成功后,可以在设备页面查看最新遥测数据。

image

设置仪表板

现在通过添加所需部件来配置仪表板。

  • 进入仪表板页面,点击+按钮创建新仪表板。

image

  • 为仪表板输入名称,然后点击添加按钮。

image

创建后仪表板将自动打开,您可以立即开始添加部件。点击添加部件

image

ThingsBoard提供了丰富的部件选择。例如,可从图表部件包中选择时序图表来可视化设备数据。

image

  • 在部件设置中,可配置展示的时间窗口
  • 数据源字段中,指定要展示数据的设备。如需添加其他数据系列,点击添加系列
  • 配置完成后,点击添加。别忘了保存仪表板。

image

示例仪表板包含室内温度图表卡片、室内湿度图表卡片以及温湿度历史曲线图。

您可以下载JSON格式的仪表板导入到您的ThingsBoard实例中。

image

发现即插即用硬件,助力您的解决方案
合作伙伴图标