node-red-contrib-sht41 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +16 -0
- package/sht41.html +99 -0
- package/sht41.js +112 -0
package/package.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "node-red-contrib-sht41",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Node-RED node to read temperature and humidity from Sensirion SHT41 sensors over I2C",
|
|
5
|
+
"keywords": ["node-red", "sht41", "temperature", "humidity", "i2c", "sensor"],
|
|
6
|
+
"author": "Your Name <youremail@example.com>",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"i2c-bus": "^5.2.2"
|
|
10
|
+
},
|
|
11
|
+
"node-red": {
|
|
12
|
+
"nodes": {
|
|
13
|
+
"sht41": "sht41.js"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
package/sht41.html
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
RED.nodes.registerType('SHT41', {
|
|
3
|
+
category: 'input',
|
|
4
|
+
color: '#1f77b4',
|
|
5
|
+
defaults: {
|
|
6
|
+
name: { value: "" },
|
|
7
|
+
busNum: { value: "1", required: true, validate: RED.validators.number() },
|
|
8
|
+
address: { value: "0x44", required: true, validate: function(v) {
|
|
9
|
+
return /^0x[0-9a-fA-F]+$|^[0-9]+$/.test(v);
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
precision: { value: "high" },
|
|
13
|
+
unit: { value: "C" }
|
|
14
|
+
},
|
|
15
|
+
inputs: 1,
|
|
16
|
+
outputs: 1,
|
|
17
|
+
icon: "font-awesome/fa-thermometer-half",
|
|
18
|
+
label: function() {
|
|
19
|
+
return this.name || "SHT41";
|
|
20
|
+
},
|
|
21
|
+
oneditprepare: function() {
|
|
22
|
+
if (this.busNum === undefined) {
|
|
23
|
+
$("#node-input-busNum").val(1);
|
|
24
|
+
}
|
|
25
|
+
$("#node-input-busNum").spinner({
|
|
26
|
+
min:0,
|
|
27
|
+
max:7
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<script type="text/html" data-template-name="SHT41">
|
|
34
|
+
|
|
35
|
+
<div class="form-row">
|
|
36
|
+
<label for="node-input-name">
|
|
37
|
+
<i class="fa fa-tag"></i> Name
|
|
38
|
+
</label>
|
|
39
|
+
<input type="text" id="node-input-name" placeholder="Name">
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<div class="form-row">
|
|
43
|
+
<label for="node-input-busNum">
|
|
44
|
+
<i class="fa fa-random"></i> I2C Bus
|
|
45
|
+
</label>
|
|
46
|
+
/dev/i2c-<input id="node-input-busNum" class="I2C-in-address" min=0 max=7 style="width:40px; height:16px;">
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<div class="form-row">
|
|
50
|
+
<label for="node-input-address">
|
|
51
|
+
<i class="fa fa-map-marker"></i> I2C Address
|
|
52
|
+
</label>
|
|
53
|
+
<input type="text" id="node-input-address">
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
<div class="form-row">
|
|
57
|
+
<label for="node-input-precision">
|
|
58
|
+
<i class="fa fa-tachometer"></i> Precision
|
|
59
|
+
</label>
|
|
60
|
+
<select id="node-input-precision">
|
|
61
|
+
<option value="high">High</option>
|
|
62
|
+
<option value="medium">Medium</option>
|
|
63
|
+
<option value="low">Low</option>
|
|
64
|
+
</select>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<div class="form-row">
|
|
68
|
+
<label for="node-input-unit">
|
|
69
|
+
<i class="fa fa-thermometer-half"></i> Unit
|
|
70
|
+
</label>
|
|
71
|
+
<select id="node-input-unit">
|
|
72
|
+
<option value="C">°C</option>
|
|
73
|
+
<option value="F">°F</option>
|
|
74
|
+
</select>
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
</script>
|
|
78
|
+
|
|
79
|
+
<script type="text/html" data-help-name="SHT41">
|
|
80
|
+
<p>
|
|
81
|
+
Reads temperature and humidity from a Sensirion SHT41 sensor over I2C.
|
|
82
|
+
</p>
|
|
83
|
+
<p>
|
|
84
|
+
Inputs:
|
|
85
|
+
</p>
|
|
86
|
+
<ul>
|
|
87
|
+
<li><b>I2C Bus</b> - I2C bus number, default is 1. This is not common to change.</li>
|
|
88
|
+
<li><b>I2C Address</b> - Address of I2C device to poll. SHT41 is 0x44 in hex, or 68 in decimal.</li>
|
|
89
|
+
<li><b>Precision</b> - Lower precision can be polled more frequently. Refer to data sheet for more information.</li>
|
|
90
|
+
<li><b>Unit</b> - Return values in Celcius or Fahrenheit.</li>
|
|
91
|
+
</ul>
|
|
92
|
+
<p>
|
|
93
|
+
Outputs:
|
|
94
|
+
</p>
|
|
95
|
+
<ul>
|
|
96
|
+
<li><code>msg.payload.temperature</code> – Temperature (°C or °F)</li>
|
|
97
|
+
<li><code>msg.payload.humidity</code> – Relative Humidity (%)</li>
|
|
98
|
+
</ul>
|
|
99
|
+
</script>
|
package/sht41.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
module.exports = function(RED) {
|
|
2
|
+
|
|
3
|
+
const i2c = require('i2c-bus');
|
|
4
|
+
|
|
5
|
+
function SHT41Node(config) {
|
|
6
|
+
RED.nodes.createNode(this, config);
|
|
7
|
+
const node = this;
|
|
8
|
+
|
|
9
|
+
node.busNumber = parseInt(config.busNum) || 1;
|
|
10
|
+
node.address = parseInt(config.address) || 0x44;
|
|
11
|
+
node.precision = config.precision || "high";
|
|
12
|
+
node.unit = config.unit || "F"; // C or F
|
|
13
|
+
|
|
14
|
+
const COMMANDS = {
|
|
15
|
+
high: 0xFD,
|
|
16
|
+
medium: 0xF6,
|
|
17
|
+
low: 0xE0
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
let bus;
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
bus = i2c.openSync(node.busNumber);
|
|
24
|
+
node.status({fill:"green",shape:"dot",text:"I2C Ready"});
|
|
25
|
+
} catch (err) {
|
|
26
|
+
node.status({fill:"red",shape:"ring",text:"I2C Error"});
|
|
27
|
+
node.error("Failed to open I2C bus: " + err.message);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// CRC-8 check (polynomial 0x31)
|
|
32
|
+
function checkCRC(data, crc) {
|
|
33
|
+
let calculated = 0xFF;
|
|
34
|
+
for (let i = 0; i < 2; i++) {
|
|
35
|
+
calculated ^= data[i];
|
|
36
|
+
for (let bit = 8; bit > 0; --bit) {
|
|
37
|
+
if (calculated & 0x80) {
|
|
38
|
+
calculated = (calculated << 1) ^ 0x31;
|
|
39
|
+
} else {
|
|
40
|
+
calculated <<= 1;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
calculated &= 0xFF;
|
|
45
|
+
return calculated === crc;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
node.on('input', function(msg) {
|
|
49
|
+
|
|
50
|
+
const command = COMMANDS[node.precision] || 0xFD;
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const cmdBuffer = Buffer.from([command]);
|
|
54
|
+
bus.i2cWriteSync(node.address, 1, cmdBuffer);
|
|
55
|
+
} catch (err) {
|
|
56
|
+
node.status({fill:"red",shape:"ring",text:"Write Error"});
|
|
57
|
+
node.error("Write Error: " + err.message, msg);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
setTimeout(() => {
|
|
62
|
+
try {
|
|
63
|
+
const buf = Buffer.alloc(6);
|
|
64
|
+
bus.i2cReadSync(node.address, 6, buf);
|
|
65
|
+
|
|
66
|
+
// CRC validation
|
|
67
|
+
if (!checkCRC([buf[0], buf[1]], buf[2]) ||
|
|
68
|
+
!checkCRC([buf[3], buf[4]], buf[5])) {
|
|
69
|
+
|
|
70
|
+
node.status({fill:"yellow",shape:"ring",text:"CRC Fail"});
|
|
71
|
+
node.error("CRC Validation Failed", msg);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const rawT = (buf[0] << 8) | buf[1];
|
|
76
|
+
const rawRH = (buf[3] << 8) | buf[4];
|
|
77
|
+
|
|
78
|
+
let temperature = -45 + 175 * (rawT / 65535);
|
|
79
|
+
const humidity = -6 + 125 * (rawRH / 65535);
|
|
80
|
+
|
|
81
|
+
if (node.unit === "F") {
|
|
82
|
+
temperature = (temperature * 9/5) + 32;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
msg.payload = {
|
|
86
|
+
temperature: parseFloat(temperature.toFixed(2)),
|
|
87
|
+
humidity: parseFloat(humidity.toFixed(2)),
|
|
88
|
+
unit: node.unit
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
node.status({fill:"green",shape:"dot",text:"T: " + msg.payload.temperature + ", H: " + msg.payload.humidity});
|
|
92
|
+
node.send(msg);
|
|
93
|
+
|
|
94
|
+
} catch (err) {
|
|
95
|
+
node.status({fill:"red",shape:"ring",text:"Read Error"});
|
|
96
|
+
node.error("Read Error: " + err.message, msg);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
}, 15);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
node.on('close', function() {
|
|
103
|
+
if (bus) {
|
|
104
|
+
try {
|
|
105
|
+
bus.closeSync();
|
|
106
|
+
} catch (err) {}
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
RED.nodes.registerType("SHT41", SHT41Node);
|
|
112
|
+
}
|