Very much agreed! For a DHT22 temperature reading just 2 bytes suffice, and for humidity even just 1 will do, without any risk of getting values that don’t fit in the text buffer.
So, for future reference: forget about examples that use text, and forget about workarounds to make that work. (And when running into those examples, point them to, e.g., this post!) Instead, see Working with Bytes to end up with something like:
// Convert the float readings from the libraries into integers to
// easily encode, send and decode.
//
// DHT22 temperature readings are -40.0 to +80.0°C ±0.5°C accuracy
// (-40.0 to 176.0°F), while a 16 bits signed integer supports -32768
// through 32767. After multiplying by 10, -400 through +1760 easily
// fits into those 2 bytes. We could even multiply by 100, but that's
// beyond the sensor's accuracy anyway. (false: return DHT22 reading
// which is Celcius; true: let the library convert it to Fahrenheit)
int16_t temp = 10 * dht.readTemperature(true);
// Humidity readings are 0-100% with 2-5% accuracy, while an 8 bits
// unsigned integer supports 0 through 255, so the measurement fits.
uint8_t hum = dht.readHumidity();
To send, we need to create a buffer in which we split the multi-byte integer values into separate bytes. Like, when showing as hexadecimal values, a temperature of -23.4 is stored in the above 16 bits signed integer as bytes 0xFF and 0x16, while 23.4 is stored as 0x00 and 0xEA. A humidity reading of 65% would read 0x41 in the 8 bits unsigned integer.
uint8_t buff[3]; // reserve 3 bytes in memory
// Handle high byte (MSB) first; 0xFF for -234 or 0x00 for +234
// 0xFF16 >> 8 shifts the 0x16 out of memory, leaving 0x00FF
// 0x00FF does not fit in a single byte, so only 0xFF is stored in buff[0]:
buff[0] = temp >> 8;
// Handle low byte (LSB) next; 0x16 for -234 or 0xEA for +234
// 0xFF16 does not fit in a single byte, so only 0x16 is stored in buff[1]:
buff[1] = temp;
// No conversion needed, just copy 0x41 for 65%:
buff[2] = hum;
// Send the 3 bytes on port 1, without asking for confirmation.
// This sends 0xFF1641 for -23.4 and 65%, or 0x00EA41 for +23.4 and 65%:
LMIC_setTxData2(1, buffer, sizeof(buff), 0);
Next, in the Payload Format in TTN Console you’ll need sign extension to support negative values (as JavaScript bitwise operators always need 32 bits), something like:
// Test using 0xFF1641 for -23.4 and 65%, or 0x00EA41 for +23.4 and 65%
function Decoder(bytes, port) {
// Sign-extend 16 bits to 32 bits to support negative values
var temp = bytes[0]<<24>>16 | bytes[1];
var hum = bytes[2];
return {
temp: temp / 10,
hum: hum
};
}
Not tested, but: no more text! And ready for further processing in Node-RED.
(Note: the first version of this post had int16_t
and uint8_t
wrong, oops. And see also Decrypting messages for dummies - #4 by arjanvanb for a bit more on the bitwise operators and sign extension.)