Payload, Uplink payload formatter & Negative Temperatures

After hours of trial and error modifying LMIC node I’ve managed to get my first temperature sensor (2x DS18B20) node working with TTN albeit postive temperatures work great. However when it comes to negative temperatures I’m stuck… having read several comments here and elsewhere on the net I was actually expecting I might come across this issue but not being a remotely competant coder I’m struggling to get anywhere with it…

I have the LMIC node preparing the uplink payload:

static volatile uint16_t temp_ = 0;
static volatile uint16_t temp2_ = 0;

uint16_t getTempValue()
{
    
    float temp;
    uint16_t tempInt;

    // Send the command to get temperatures
    ds18b20_sensors.requestTemperatures();
    temp = ds18b20_sensors.getTempCByIndex(0);
    tempInt = temp * 100;

    #ifdef USE_SERIAL
        printSpaces(serial, MESSAGE_INDENT);
        serial.print(F("TEMP value: "));
        Serial.println(temp);
    #endif  

  return tempInt;

}

uint16_t getTemp2Value()
{

    float temp2;
    uint16_t temp2Int;

    // Send the command to get temperatures
    ds18b20_sensors.requestTemperatures();
    temp2 = ds18b20_sensors.getTempCByIndex(1);
    temp2Int = temp2 * 100;

    #ifdef USE_SERIAL
        printSpaces(serial, MESSAGE_INDENT);
        serial.print(F("TEMP 2 value: "));
        Serial.println(temp2);
    #endif  

  return temp2Int;

    
}





void processWork(ostime_t doWorkJobTimeStamp)
{
    // This function is called from the doWorkCallback() 
    // callback function when the doWork job is executed.

    // Uses globals: payloadBuffer and LMIC data structure.

    // This is where the main work is performed like
    // reading sensor and GPS data and schedule uplink
    // messages if anything needs to be transmitted.

    // Skip processWork if using OTAA and still joining.
    if (LMIC.devaddr != 0)
    {
        // Collect input data.

        uint16_t tempValue = getTempValue();
        uint16_t temp2Value = getTemp2Value();
        ostime_t timestamp = os_getTime();

        #ifdef USE_DISPLAY
            // Interval and Counter values are combined on a single row.
            // This allows to keep the 3rd row empty which makes the
            // information better readable on the small display.
            display.clearLine(INTERVAL_ROW);
            display.setCursor(COL_0, INTERVAL_ROW);
            display.print("I:");
            display.print(doWorkIntervalSeconds);
            display.print("s");        
            display.print(" Ctr:");
            display.print(tempValue);
        #endif
        
       /* #ifdef USE_SERIAL
            printEvent(timestamp, "Input data collected", PrintTarget::Serial);
            printSpaces(serial, MESSAGE_INDENT);
            serial.print(F("TEMP value: "));
            serial.println(tempValue);
            printSpaces(serial, MESSAGE_INDENT);
            serial.print(F("TEMP2 value: "));
            serial.println(temp2Value);
        #endif    
        */


        // For simplicity LMIC-node will try to send an uplink
        // message every time processWork() is executed.

        // Schedule uplink message if possible
        if (LMIC.opmode & OP_TXRXPEND)
        {
            // TxRx is currently pending, do not send.
            #ifdef USE_SERIAL
                printEvent(timestamp, "Uplink not scheduled because TxRx pending", PrintTarget::Serial);
            #endif    
            #ifdef USE_DISPLAY
                printEvent(timestamp, "UL not scheduled", PrintTarget::Display);
            #endif
        }
        else
        {
            // Prepare uplink payload.
            uint8_t fPort = 10;
            payloadBuffer[0] = (tempValue >> 8) & 0xff;
            payloadBuffer[1] = tempValue & 0xFF;
            payloadBuffer[2] = (temp2Value >> 8) & 0xff;
            payloadBuffer[3] = temp2Value & 0xFF;
            uint8_t payloadLength = 8;

            scheduleUplink(fPort, payloadBuffer, payloadLength);
        }
    }
}    
 

void processDownlink(ostime_t txCompleteTimestamp, uint8_t fPort, uint8_t* data, uint8_t dataLength)
{
    // This function is called from the onEvent() event handler
    // on EV_TXCOMPLETE when a downlink message was received.

    // Implements a 'reset counter' command that can be sent via a downlink message.
    // To send the reset counter command to the node, send a downlink message
    // (e.g. from the TTN Console) with single byte value resetCmd on port cmdPort.

    const uint8_t cmdPort = 100;
    const uint8_t resetCmd= 0xC0;

    if (fPort == cmdPort && dataLength == 1 && data[0] == resetCmd)
    {
        #ifdef USE_SERIAL
            printSpaces(serial, MESSAGE_INDENT);
            serial.println(F("Reset cmd received"));
        #endif
        ostime_t timestamp = os_getTime();
        //resetCounter();
        printEvent(timestamp, "Counter reset", PrintTarget::All, false);
    }          
}

And for the the Uplink Decoder I have:

function Decoder(bytes, port) {
  
  var temp = ((bytes[0]<<8 | bytes[1]) & 0x3FFF)/ 100;
  var temp2 = ((bytes[2]<<8 | bytes[3]) & 0x3FFF)/ 100;
  
  return {
    Temp: temp,
    Temp2: temp2,
      
  };
}

Can anyone suggest how I might go about getting a sensible value for neative temperatures, or at least point me in the right direction…

Use an offset, so you add 100 or some such number (so that can go down to -100) to your temp:

uint16_t tempInt = (uint16_t) ((temp + 100.0) * 100.0);

and at the other end:

var temp = ( (bytes[0] << 8) + bytes[1]) / 100 ) - 100;

So -10.54C becomes 89.46 becomes 8946 and is reversed to 89.46, the -100 = -10.54.

With an uint16_t and 2 decimal places (a suspect level of accuracy, 1 dp should be sufficient unless you are NASA), you’ve got 655.35 so you adjust the 100 as appropriate - Alaskan residents may need -150. I have seen a -327.5 before now to split the difference, but there is an ongoing debate at what happens at negative values of Kelvin …

This may help as well: https://www.thethingsnetwork.org/docs/devices/bytes/ - ignore the pink message, this page is still very relevant. This is linked from the v3 docs so worth exploring the payload formatters section there as well.

1 Like

Thank you Nick, that’s very helpful indeed! I had convinced myself my coding inability was at fault and I was clearly missing some clever coding tricks when the the answer, infact, could be reached with some basic maths :man_facepalming:

read this post

but rené post will get you there

hope i am quoting the correct one

1 Like

Thank you both for the replies after a bit more trial and error I’ve got it working as expected. Lesson learnt… don’t get bogged down with the complicated stuff and overlook the simple things :man_facepalming:

Or just ask nicely with some evidence of prior effort - just like you did - always a pleasure to help people with that next step when they’ve got snow-blind - happens to me all the time!

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.