How to use the DHT22 with LMiC?


(K5at) #1

I am using a Draguino shield with a Aduino Uno and the Lmic library. I am not a programmer, just a hack, and would appreciate your help on this project. Thanks.

I currently have it sending temperature data for a DHT22 to the network, and that is working OK.

The problem is that I also want to send the humidity data also. Where I get hung up is putting both the temp and humidity data in the right format for the following:

float temp = (dht.readTemperature(true));
float hum = (dht.readHumidity());

char buff[5];
char buff1[10];
char mydata;
dtostrf(temp, 4, 1, buff);
dtostrf(hum, 4, 1, buff1);
//String data =buff;
//String data1 =buff1;
//String databuf = String(data +" "+ data1);
//Serial.println(databuf);

LMIC_setTxData2(1,buff,sizeof(buff)-1,0);

#2

something like that should do the trick

char buff[15];
dtostrf(temp, 5, 1, buff);
strcat(buff, " ");
dtostrf(hum, 5, 1, buff+strlen(buff));
LMIC_setTxData2(1,buff,strlen(buff),0);

or if you want to keep 2 buffers + 1 temp (not really optimized)

char bufftemp[6];
char buffhum[6];
char buff[sizeof(bufftemp)+sizeof(buffhum)-1];
dtostrf(temp, 5, 1, bufftemp);
dtostrf(hum, 5, 1, buffhum);
sprintf(buff, "%s %s", bufftemp, buffhum);
// or even better
//sprintf_P(buff, PSTR("%s %s"), bufftemp,buffhum);
LMIC_setTxData2(1,buff,strlen(buff),0);

take care that dtostrf(temp, 4, 1, buff) will get you in trouble as soon as temp <= -10°C because -10.5 is 5 char

But I suggest not to send values as string or char array, it’s not LoRaWAN optimized.
A temperature + Humidity could fit in 3 bytes instead of 3 x more in your case.


(K5at) #3

The first suggestion works perfectly. Thanks you very much.
now on to node-red and getting the data in my desired format…
Thanks from an old man in Texas!


(Arjan) #4

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 for a bit more on the bitwise operators and sign extension.)


Need Help: Feather M0 Programming
(K5at) #5

I tried the above, but couldn’t get the decoder to work properly.
I’m back on Charles fix which work fine on an Arduino Uno, but I get an error using a Heltec Lora Module.

Lora_Heltec_Copy:152:45: error: invalid conversion from ‘char*’ to ‘xref2u1_t {aka unsigned char*}’ [-fpermissive]
LMIC_setTxData2(1, buff, strlen(buff), 0);
this is the code that I’m using, and again, it works fine using a Arduino Uno.

float temp = (dht.readTemperature(true));
float hum = (dht.readHumidity());
dtostrf(temp, 5, 1, buff);
strcat(buff, " ");
dtostrf(hum, 5, 1, buff + strlen(buff));
LMIC_setTxData2(1, buff, strlen(buff), 0);

Any Ideas?


(Arjan) #6

What problems are you running into? Did you test with the bytes I gave you? (Without the hexadecimal 0x prefix.) That seems to work for me:

Payload Format

What payload does TTN Console show?


You might need to change:

…into something Iike:

byte buff[15];

or:

unsigned char buff[15];

Obviously, your didn’t hear that from me. No. More. Text. Examples. :wink: