202 lines
No EOL
8 KiB
HTML
202 lines
No EOL
8 KiB
HTML
<!doctype html>
|
|
|
|
<html>
|
|
<head>
|
|
<title>AttNode v3 Payload Decoder Generator</title>
|
|
<meta name="description" content="AttNode v3 Payload Decoder Generator">
|
|
<meta name="author" content="Stefan Brand">
|
|
<style>
|
|
body {
|
|
background-color: #e9eaec;
|
|
font-family: Roboto, sans-serif;
|
|
font-size: 1em;
|
|
padding: 24px;
|
|
}
|
|
div {
|
|
background: #f8f8f8;
|
|
border: 1px solid #ccc;
|
|
padding: 1em 2em;
|
|
margin-bottom: 40px;
|
|
}
|
|
|
|
pre {
|
|
border: 1px solid black;
|
|
font-family: monospace, monospace;
|
|
font-size: 1em;
|
|
padding: 4px;
|
|
}
|
|
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div class="title">
|
|
<h1>AttNode v3 Payload Decoder Generator</h1>
|
|
</div>
|
|
<div class="header">
|
|
<p>Please choose the Sensors that you have enabled in the Firmware. The Payload Decoder code below will change accordingly.</p>
|
|
<p>Notes:</p>
|
|
<ul>
|
|
<li>You can set arbitary combinations of Sensors here. Not all of them are useable / technically possible</li>
|
|
<li>Enable only the sensors in the decoder, which are enabled in the firmware for a particular device. The Decoder does not detect which sensors are present in the LoRa paket. You can set a payload decoder per device in TTN v3 to have nodes with different sensors in one application</li>
|
|
<li>The Payload Decoder shown here is for TTN v3 / The Things Stack v3. If you use other LoRa Stacks you may have to change the <b>decodeUplink</b> function and its return value.</li>
|
|
</ul>
|
|
</div>
|
|
<div class="chooser">
|
|
<h3>Sensors:</h3>
|
|
<form id="chooserForm">
|
|
<label>
|
|
<input type="checkbox" value="mhz19c" onchange="updateDecoder();">
|
|
MH-Z19C
|
|
</label>
|
|
<label>
|
|
<input type="checkbox" value="sg112a" onchange="updateDecoder();">
|
|
SG112A
|
|
</label>
|
|
<label>
|
|
<input type="checkbox" value="sensairs8" onchange="updateDecoder();">
|
|
Sensair S8
|
|
</label>
|
|
<label>
|
|
<input type="checkbox" value="scd30" onchange="updateDecoder();">
|
|
SCD30
|
|
</label>
|
|
<label>
|
|
<input type="checkbox" value="bme280" onchange="updateDecoder();">
|
|
BME280
|
|
</label>
|
|
<label>
|
|
<input type="checkbox" value="sht21" onchange="updateDecoder();">
|
|
SHT21
|
|
</label>
|
|
<label>
|
|
<input type="checkbox" value="sps30" onchange="updateDecoder();">
|
|
SPS30
|
|
</label>
|
|
<label>
|
|
<input type="checkbox" value="hm330x" onchange="updateDecoder();">
|
|
HM330x
|
|
</label>
|
|
<label>
|
|
<input type="checkbox" value="brightness" onchange="updateDecoder();">
|
|
Brightness
|
|
</label>
|
|
<label>
|
|
<input type="checkbox" value="ds18b20" onchange="updateDecoder();">
|
|
DS18B20
|
|
</label>
|
|
</form>
|
|
<h3>Payload Decoder:</h3>
|
|
<pre id="pd">
|
|
</pre>
|
|
</div>
|
|
|
|
<a href="https://www.attno.de/">Back to attno.de Main Page</a>
|
|
<script>
|
|
var sensors = {
|
|
"mhz19c": [
|
|
{ "name": "co2ppm", "type": "UInt16", "factor": 1, "multi": false },
|
|
],
|
|
"sg112a": [
|
|
{ "name": "co2ppm", "type": "UInt16", "factor": 1, "multi": false },
|
|
],
|
|
"sensairs8": [
|
|
{ "name": "co2ppm", "type": "UInt16", "factor": 1, "multi": false },
|
|
],
|
|
"scd30": [
|
|
{ "name": "co2ppm", "type": "UInt16", "factor": 1, "multi": false },
|
|
{ "name": "temperature", "type": "Int16", "factor": 100, "multi": false },
|
|
{ "name": "humidity", "type": "UInt16", "factor": 100, "multi": false },
|
|
],
|
|
"bme280": [
|
|
{ "name": "temperature", "type": "Int32", "factor": 100, "multi": false },
|
|
{ "name": "humidity", "type": "Int32", "factor": 100, "multi": false },
|
|
{ "name": "pressure", "type": "Int32", "factor": 100, "multi": false },
|
|
],
|
|
"sht21": [
|
|
{ "name": "temperature", "type": "Int32", "factor": 100, "multi": false },
|
|
{ "name": "humidity", "type": "Int32", "factor": 100, "multi": false },
|
|
],
|
|
"sps30": [
|
|
{ "name": "pm1", "type": "UInt16", "factor": 1, "multi": false },
|
|
{ "name": "pm2_5", "type": "UInt16", "factor": 1, "multi": false },
|
|
{ "name": "pm4", "type": "UInt16", "factor": 1, "multi": false },
|
|
{ "name": "pm10", "type": "UInt16", "factor": 1, "multi": false },
|
|
{ "name": "typPMsize", "type": "UInt16", "factor": 1, "multi": false },
|
|
],
|
|
"hm330x": [
|
|
{ "name": "pm1", "type": "UInt16", "factor": 1, "multi": false },
|
|
{ "name": "pm2_5", "type": "UInt16", "factor": 1, "multi": false },
|
|
{ "name": "pm10", "type": "UInt16", "factor": 1, "multi": false },
|
|
],
|
|
"brightness": [
|
|
{ "name": "brightness", "type": "UInt16", "factor": 1, "multi": false },
|
|
],
|
|
"ds18b20": [
|
|
{ "name": "t", "type": "Int16", "factor": 100, "multi": true },
|
|
]
|
|
};
|
|
var typelen = {"Int32": "4", "Int16": "2", "UInt16": "2"};
|
|
|
|
function updateDecoder() {
|
|
var output = document.getElementById("pd");
|
|
|
|
output.innerHTML = "function bytesToInt16(bytes, start) {\n";
|
|
output.innerHTML += " var out = ((bytes[start]) | (bytes[start+1] << 8 ));\n";
|
|
output.innerHTML += " var sign = bytes[start+1] & (1 << 7);\n";
|
|
output.innerHTML += " if (sign)\n";
|
|
output.innerHTML += " out = 0xFFFF0000 | out;\n";
|
|
output.innerHTML += " return out;\n";
|
|
output.innerHTML += "}\n\n";
|
|
output.innerHTML += "function bytesToUInt16(bytes, start) {\n";
|
|
output.innerHTML += " return ((bytes[start]) | (bytes[start+1] << 8 ));\n";
|
|
output.innerHTML += "}\n\n";
|
|
output.innerHTML += "function bytesToInt32(bytes, start) {\n";
|
|
output.innerHTML += " return ((bytes[start]) | (bytes[start+1] << 8) | (bytes[start+2] << 16) | (bytes[start+3] << 24));\n";
|
|
output.innerHTML += "}\n\n";
|
|
output.innerHTML += "function decodeUplink(input) {\n";
|
|
output.innerHTML += " var decoded = {};\n";
|
|
output.innerHTML += " /* Battery Voltage, always enabled */\n";
|
|
output.innerHTML += " decoded.v = (input.bytes[0] * 20) / 1000.0;\n\n";
|
|
output.innerHTML += " var i = 1;\n";
|
|
|
|
var elements = document.getElementById("chooserForm").elements;
|
|
|
|
for (var i = 0, element; element = elements[i++];) {
|
|
if (element.type === "checkbox")
|
|
if (element.checked) {
|
|
sensors[element.value].forEach(sensor => {
|
|
if (sensor.multi) {
|
|
output.innerHTML += " var n = 1;\n";
|
|
output.innerHTML += " for (var j = i; j < input.bytes.length-1; j+=2) {\n";
|
|
if (sensor.factor > 1) {
|
|
output.innerHTML += " decoded['" + sensor.name + "' + n] = bytesTo" + sensor.type + " (input.bytes, j);\n";
|
|
} else {
|
|
output.innerHTML += " decoded['" + sensor.name + "' + n] = bytesTo" + sensor.type + " (input.bytes, j)/" + sensor.factor + ";\n";
|
|
}
|
|
output.innerHTML += " n++;\n";
|
|
output.innerHTML += " }\n";
|
|
|
|
} else {
|
|
if (sensor.factor > 1) {
|
|
output.innerHTML += " decoded." + sensor.name + " = bytesTo" + sensor.type + "(input.bytes, i)/" + sensor.factor + ";\n";
|
|
} else {
|
|
output.innerHTML += " decoded." + sensor.name + " = bytesTo" + sensor.type + "(input.bytes, i);\n";
|
|
}
|
|
output.innerHTML += " i += " + typelen[sensor.type] + ";\n";
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
output.innerHTML += "\n\n return {\n";
|
|
output.innerHTML += " data: decoded,\n";
|
|
output.innerHTML += " warnings: [],\n";
|
|
output.innerHTML += " errors: []\n";
|
|
output.innerHTML += " };\n";
|
|
output.innerHTML += "}\n";
|
|
}
|
|
|
|
</script>
|
|
</body>
|
|
</html> |