Temperature monitoring with lora

IMG_20151216_134116This is how I programmed the NUCLEO-L152RE microcontroller and Grove – Temperature&Humidity Sensor Pro to monitor temperature and humidity. The temperature readings are shipped off to the things network via our LoRaWAN network.

The purpose of this is to help others get started using the LoRaWAN technology to build IOT applications.

ALSO READ: Sending text with lorawan towards the things network

Grove – Temperature and Humidity Sensor Pro

To read temperature data from the Grove sensor I imported the DHT C++ library. Next I added an include for the header file

#include "DHT.h"

The temperature is read with

DHT sensor(A1, AM2302); // AM2302 is the product name of the sensor
int err = sensor.readData();

float getTemperature() {

    int err = 1;
    while(err != 0) {
        wait(2.0f); // Wait 2 seconds
        err = sensor.readData();
    return sensor.ReadTemperature(CELCIUS);

The humidity sensor is accessed in a similar way: sensor.ReadHumidity()

I plugged the grove sensor into A0 of the grove shield. This turned out not to work because the Semtech lora transceiver uses this port for NRESET. I used A1 instead.

I’m occasionally getting

Err 6

from sensor.readData(), which is a checksum (CRC) error.
To get a temperature value without error, I read the sensor in a loop until there is no error.

After a few flashings of binary onto the microcontroller I got this error:

Jan 18 11:11:15 bergman kernel: VFS: busy inodes on changed media or resized disk sdb
cp: error writing ‘/media/d/NODE_L152RE/LoRaWAN_send_text_2_NUCLEO_L152RE.bin’: No space left on device
cp: failed to extend ‘/media/d/NODE_L152RE/LoRaWAN_send_text_2_NUCLEO_L152RE.bin’: No space left on device

I’m unable to repair the root cause of this. But replugging the device fixes the symptom.

To execute the temperature reading code each 60s I add this at the end of the onSendFrame function:

os_setTimedCallback(j, os_getTime() + sec2osticks(60), onSendFrame);

Live demo


See our live demo for real-time humidity and temperature readings! Also see our github repo for its code.

The things network API do not support TLS yet. I had to add an exception in our apache config to circumvent browser blocking of non-TLS content:

RewriteRule ^/demo/lora-temperature - [L]

The full code

#include "mbed.h"
#include "lmic.h"
#include "debug.h"
#include "Serial.h"

#include "DHT.h"

#define LORAWAN_NET_ID (uint32_t) 0x00000000
#define LORAWAN_DEV_ADDR (uint32_t) 0x02031003
#define LORAWAN_ADR_ON 1
#define LORAWAN_APP_PORT 3//15

DHT sensor(A1, AM2302);

Serial co2(D8, D2);

static uint8_t NwkSKey[] = {
    0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 
    0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C

static uint8_t ArtSKey[] = {
    0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 
    0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C

osjob_t initjob;
osjob_t sendFrameJob;
u1_t n = 0;

void os_getArtEui (uint8_t *buf) {} // ignore
void os_getDevEui (uint8_t *buf) {} // ignore
void os_getDevKey (uint8_t *buf) {} // ignore

float getTemperature() {

    int err = 1;
    while(err != 0) {
        err = sensor.readData();
    return sensor.ReadTemperature(CELCIUS);

float getHumidity() {
    return sensor.ReadHumidity();
void onSendFrame (osjob_t* j) {
    const unsigned char cmd_get_sensor[] = {
        0xff, 0x01, 0x86, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x79

    for (int i = 0; i < 9; i++) {
    char message[32];
    float temperature = getTemperature();
    printf("Temperature is %4.2f \r\n", temperature);
    float humidity = getHumidity();
    printf("Humidity is %4.2f \r\n", humidity);

    sprintf(message, "%4.2f %4.2f", temperature, humidity);
    int frameLength = strlen(message); // keep it < 32
    for (int i = 0; i < frameLength; i++) {
        LMIC.frame[i] = message[i];
    int result = LMIC_setTxData2(LORAWAN_APP_PORT, LMIC.frame, 
        frameLength, LORAWAN_CONFIRMED_MSG_ON); // calls onEvent()
    os_setTimedCallback(j, os_getTime() + sec2osticks(60), onSendFrame);

void onInit (osjob_t* j) {
    LMIC_setDrTxpow(DR_SF12, 14);

void onEvent (ev_t ev) { // called by lmic.cpp, see also oslmic.h
    if (ev == EV_TXCOMPLETE) {
        os_setCallback(&sendFrameJob, onSendFrame);

int main (void) {
    debug_str("Entered main\r\n");
    os_setCallback(&initjob, onInit);
    os_runloop(); // blocking